#6575·3x-ui

[Bug]: Subscription: `?serverDescription=` in client external links (kind=link) gets percent-encoded, Happ subtitle is lost

Author: runovsCreated Sep 16, 2026Updated Sep 16, 2026
Labelsbug

Describe the bug

Happ shows a subtitle under the server name when the link fragment is #<name>?serverDescription=<base64> (documented by Happ; 3x-ui already keeps it literal for inbound/host links since #6488).

For client external links (POST /panel/api/clients/{email}/externalLinks, kind: "link") the fragment is stored correctly, but the generated subscription re-encodes it: ? becomes %3F and / inside the base64 becomes %2F. Happ no longer recognises the parameter and the subtitle disappears. The same link imported into Happ manually (not via the subscription) shows the subtitle correctly.

#6488 added strings.Cut handling of ?serverDescription= in appendQueryAndFragment for links built from inbounds/hosts. External link rows appear to go through a different path that escapes the whole fragment. Applying the same split there (escape only the name, keep ?serverDescription=<base64> literal, validate the tail for #, &, spaces and newlines) would fix it.

External links are the main use case for operators who aggregate servers from several sources, so hosts-level serverDescription does not cover them.

How to reproduce the problem

  1. Add an external link to a client via POST /panel/api/clients/{email}/externalLinks (or the client's "Links" tab):
    json
    {"externalLinks":[{"kind":"link","enable":true,"value":"vless://[email protected]:443?type=tcp&security=reality&pbk=XXX&fp=chrome&sni=example.org&sid=00&flow=xtls-rprx-vision&encryption=none# Warsaw ⚡️?serverDescription=0JTQu9GPIExURSAo0LHQtdC70YvQtSDRgdC/0LjRgdC60Lgp"}]}
  2. GET /panel/api/clients/get/{email} — the value is stored unchanged.
  3. Fetch that client's subscription URL and base64-decode it.
  4. Observe the fragment of the external link line: ?serverDescription= is escaped to %3FserverDescription=.
  5. Add the subscription to Happ — no subtitle. Import the same vless:// link into Happ directly — the subtitle is shown.

Expected behavior

The name part may be percent-encoded, but ?serverDescription= and its base64 value stay literal:

#%F0%9F%87%B5%F0%9F%87%B1%20Warsaw%20%E2%9A%A1%EF%B8%8F?serverDescription=0JTQu9GPIExURSAo0LHQtdC70YvQtSDRgdC/0LjRgdC60Lgp

Actual behavior

#%F0%9F%87%B5%F0%9F%87%B1%20Warsaw%20%E2%9A%A1%EF%B8%8F%3FserverDescription=0JTQu9GPIExURSAo0LHQtdC70YvQtSDRgdC%2F0LjRgdC60Lgp

Happ does not show the subtitle.

Relevant logs

bash

Screenshots

Image

3x-ui version

3.7.0

Xray-core version

26.7.28

How did you install 3x-ui?

install.sh script

Operating system

Ubuntu 24.04

Which parts of the panel are affected?

Subscription (share links / Clash / JSON)

Browser (only if it is a UI bug)

No response

Is the panel behind a reverse proxy or CDN?

None

Before submitting

  • I searched existing issues and this bug has not been reported.
  • I am running the latest released version of 3x-ui (or have verified the bug still exists on it).
  • This bug report is written in English.
  • I have redacted any sensitive data (tokens, real domains, client UUIDs).