Note: This issue was generated and submitted by an automated AI review tool after
automated analysis of the published output/clash.yaml. The findings below were verified
against real Clash.Meta (mihomo v1.19.9) behavior with mihomo -t, not just static
inspection. Details such as node names/counts come directly from the generated file.
Summary
The published subscription output/clash.yaml cannot be imported into
Clash.Meta-based clients (FLClash, Clash Verge Rev, mihomo, Clash Meta for
Android, etc.). Import fails immediately with:
yaml: control characters are not allowed
This is a hard parsing failure produced by go-yaml v3 — the YAML parser
embedded in the mihomo/Clash.Meta kernel. It rejects the whole file, so no
proxies are loaded at all. In addition to this blocking bug, ~237 of the 1996
nodes (~12%) carry invalid fields that either fail to parse or can never
establish a connection.
1. Root cause of the import failure (fatal)
The file contains raw non-ASCII / control-range bytes written literally
into the YAML. The exact offender is node vless-459568923, whose network
value embeds an emoji variation selector U+FE0F (bytes 0xEF 0xB8 0x8F):
- name: vless-459568923
network: "tcp#\U0001F397\xef\xb8\x8f98@oneclickvpnkeys"
- The string contains the literal escape
\U0001F397 (🎗️), followed by the
raw three bytes \xef\xb8\x8f (U+FE0F variation selector) written into the
file.
- go-yaml v3's scanner checks every byte with its
is_printable() table and
flags these bytes as control characters → yaml: control characters are not allowed → whole file rejected.
- PyYAML (used by many local test scripts) is lenient about these bytes, which
is why the file "passes" some local checks but fails in real Clash.Meta
clients.
- Note: earlier quick scans that only look at bytes
< 0x20 will NOT catch
this — the offending bytes are in the C1 range (0x7F–0x9F), which is
exactly why a byte-scan must replicate yaml.v3's printable check.
This single 3-byte sequence in one node bricks the entire subscription for
Clash.Meta users.
2. Invalid network values (80 nodes)
network: raw is not a valid transport for vless/vmess in Clash.Meta.
Supported values are tcp / udp / ws / grpc / h2 / http / xhttp.
"raw" is a sing-box/Xray internal term and does not exist in Clash.Meta.
Examples (80 total):
- name: vless-262807486
type: vless
network: raw # invalid, should be tcp
- name: vmess-485686543
type: vmess
network: raw # invalid, should be tcp
3. vless/gRPC nodes missing grpc-opts.serviceName (24 nodes)
Clash.Meta requires grpc-opts.serviceName for network: grpc. Without it the
gRPC transport cannot complete the handshake.
- name: vless-330581942
type: vless
network: grpc # missing grpc-opts.serviceName
4. Reality nodes with empty short-id (30 nodes)
REALITY handshake requires a non-empty short-id. Nodes with short-id: ""
can never connect and only pollute the list. Example:
- name: vless-549947446
type: vless
tls: true
reality-opts:
public-key: kdlgIBl7R_1DIWtJIrOqYwt65nedPCbz6XoomdpQIXM
short-id: "" # empty — REALITY can never handshake
5. Invalid sni values — URL / t.me link / emoji (14 nodes)
sni must be a plain hostname (or IP). These nodes put URLs, Telegram links,
or emoji into sni, which breaks the TLS/QUIC handshake:
- name: hysteria2-467420662
sni: "https://t.me/oneclickvpnkeys" # URL, not a hostname
- name: hysteria2-467980788
sni: "https://t.me/clashv8🇨🇳" # URL + emoji
- name: trojan-429843172
sni: t.me/ripaojiedian # Telegram path
- name: trojan-133769367
sni: t.me%2fripaojiedian # percent-encoded path
- name: hysteria2-483633865
sni: "https://t.me/wangcai2…" # contains C1 bytes
- name: hysteria2-483633864
sni: "https://t.me/wangcai2рҹүёрҹүі" # mojibake
(6 more nodes use sni: "t.me" alone.)
6. ws nodes missing ws-opts (83 nodes)
vless/vmess with network: ws should carry ws-opts (path, headers.Host).
Without a path the WebSocket upgrade almost always fails. Examples (83 total):
- name: vmess-145260
type: vmess
network: ws # missing ws-opts
- name: vless-463880255
type: vless
network: ws # missing ws-opts
Impact summary
| # |
Issue |
Count |
| 0 |
Control bytes in YAML → whole file rejected (fatal) |
1 node, 3 bytes |
| 1 |
network: raw (invalid transport) |
80 |
| 2 |
gRPC missing grpc-opts.serviceName |
24 |
| 3 |
Reality empty short-id |
30 |
| 4 |
Invalid sni (URL / t.me / emoji) |
14 |
| 5 |
ws missing ws-opts |
83 |
|
Total affected |
~237 / 1996 (~12%) |
Two additional observations worth noting for the generator pipeline:
- Node names are globally unique (no duplicates) — good.
- The structure (
proxies / proxy-groups / rules) is otherwise
well-formed; groups reference only existing nodes.
Suggested fixes for the generator
- Sanitize output to pure ASCII: escape or strip every non-ASCII byte
(write \uXXXX escapes or drop emoji) before writing the YAML — this alone
fixes the fatal import bug.
- Normalize
network: raw → tcp during conversion.
- Always emit
grpc-opts.serviceName for network: grpc nodes, or drop them.
- Skip Reality nodes whose
short-id / public-key are empty.
- Validate
sni is a bare hostname/IP: strip scheme, path, t.me fragments,
and emoji; fall back to servername/server when invalid.
- Always emit
ws-opts for ws nodes (at least a default path: /).
Verification
After applying the above, a sanitized profile (ASCII-only, 1966 nodes after
dropping 30 broken Reality nodes) was validated with the real kernel:
$ mihomo -t -f clash.meta.yaml
configuration file clash.meta.yaml test is successful
Happy to share the sanitizing script or a patched clash.yaml if useful.
Summary
The published subscription
output/clash.yamlcannot be imported intoClash.Meta-based clients (FLClash, Clash Verge Rev, mihomo, Clash Meta for
Android, etc.). Import fails immediately with:
This is a hard parsing failure produced by go-yaml v3 — the YAML parser
embedded in the mihomo/Clash.Meta kernel. It rejects the whole file, so no
proxies are loaded at all. In addition to this blocking bug, ~237 of the 1996
nodes (~12%) carry invalid fields that either fail to parse or can never
establish a connection.
1. Root cause of the import failure (fatal)
The file contains raw non-ASCII / control-range bytes written literally
into the YAML. The exact offender is node
vless-459568923, whosenetworkvalue embeds an emoji variation selector U+FE0F (bytes
0xEF 0xB8 0x8F):\U0001F397(🎗️), followed by theraw three bytes
\xef\xb8\x8f(U+FE0F variation selector) written into thefile.
is_printable()table andflags these bytes as control characters →
yaml: control characters are not allowed→ whole file rejected.is why the file "passes" some local checks but fails in real Clash.Meta
clients.
< 0x20will NOT catchthis — the offending bytes are in the C1 range (0x7F–0x9F), which is
exactly why a byte-scan must replicate yaml.v3's printable check.
This single 3-byte sequence in one node bricks the entire subscription for
Clash.Meta users.
2. Invalid
networkvalues (80 nodes)network: rawis not a valid transport forvless/vmessin Clash.Meta.Supported values are
tcp/udp/ws/grpc/h2/http/xhttp."raw" is a sing-box/Xray internal term and does not exist in Clash.Meta.
Examples (80 total):
3. vless/gRPC nodes missing
grpc-opts.serviceName(24 nodes)Clash.Meta requires
grpc-opts.serviceNamefornetwork: grpc. Without it thegRPC transport cannot complete the handshake.
4. Reality nodes with empty
short-id(30 nodes)REALITY handshake requires a non-empty
short-id. Nodes withshort-id: ""can never connect and only pollute the list. Example:
5. Invalid
snivalues — URL /t.melink / emoji (14 nodes)snimust be a plain hostname (or IP). These nodes put URLs, Telegram links,or emoji into
sni, which breaks the TLS/QUIC handshake:(6 more nodes use
sni: "t.me"alone.)6. ws nodes missing
ws-opts(83 nodes)vless/vmess with
network: wsshould carryws-opts(path,headers.Host).Without a path the WebSocket upgrade almost always fails. Examples (83 total):
Impact summary
network: raw(invalid transport)grpc-opts.serviceNameshort-idsni(URL / t.me / emoji)ws-optsTwo additional observations worth noting for the generator pipeline:
proxies/proxy-groups/rules) is otherwisewell-formed; groups reference only existing nodes.
Suggested fixes for the generator
(write
\uXXXXescapes or drop emoji) before writing the YAML — this alonefixes the fatal import bug.
network: raw→tcpduring conversion.grpc-opts.serviceNamefornetwork: grpcnodes, or drop them.short-id/public-keyare empty.sniis a bare hostname/IP: strip scheme, path,t.mefragments,and emoji; fall back to
servername/serverwhen invalid.ws-optsfor ws nodes (at least a defaultpath: /).Verification
After applying the above, a sanitized profile (ASCII-only, 1966 nodes after
dropping 30 broken Reality nodes) was validated with the real kernel:
Happy to share the sanitizing script or a patched
clash.yamlif useful.