MHSanaei/3x-ui · warning
unsupported link scheme
Error message
unsupported link scheme
What it means
Returned by ParseOutbound when the link matches none of the recognized prefixes: vmess://, vless://, trojan://, ss://, hysteria2:// or hy2://, wireguard:// or wg://. It is the dispatcher's default branch — pure input validation, no state is touched. Callers that iterate over subscription lists will hit this on any foreign or mistyped link.
Source
Thrown at internal/util/link/outbound.go:127
// - hysteria2:// (also hy2://)
// - wireguard:// (also wg://)
func ParseLink(link string) (*ParseResult, error) {
link = strings.TrimSpace(link)
switch {
case strings.HasPrefix(link, "vmess://"):
return parseVmess(link)
case strings.HasPrefix(link, "vless://"):
return parseVless(link)
case strings.HasPrefix(link, "trojan://"):
return parseTrojan(link)
case strings.HasPrefix(link, "ss://"):
return parseShadowsocks(link)
case strings.HasPrefix(link, "hysteria2://"), strings.HasPrefix(link, "hy2://"):
return parseHysteria2(link)
case strings.HasPrefix(link, "wireguard://"), strings.HasPrefix(link, "wg://"):
return parseWireguard(link)
default:
return nil, fmt.Errorf("unsupported link scheme")
}
}
// --- vmess ---
func parseVmess(link string) (*ParseResult, error) {
b64 := strings.TrimPrefix(link, "vmess://")
// vmess:// base64(json)
raw, err := base64.StdEncoding.DecodeString(padBase64(b64))
if err != nil {
// Some providers use raw URL-safe
raw, err = base64.RawURLEncoding.DecodeString(b64)
}
if err != nil {
return nil, fmt.Errorf("vmess decode: %w", err)
}
var j map[string]any
if err := json.Unmarshal(raw, &j); err != nil {View on GitHub (pinned to ad32144c42)
Solutions
- Print/trim the failing link and check its scheme against the supported list before retrying.
- Filter or skip unsupported entries when batch-parsing instead of aborting the whole list.
- Convert ssr:// or tuic:// links manually (or extend the dispatcher's prefix table if you control the fork).
- Ensure the link still contains '://' — some clients copy 'vmess:eyJ...' without the slashes.
Example fix
// before: aborting a whole batch on one bad link
for _, l := range links {
res, err := link.ParseOutbound(l)
if err != nil { return err }
}
// after: skip unparseable entries
for _, l := range links {
res, err := link.ParseOutbound(l)
if err != nil {
if strings.Contains(err.Error(), "unsupported link scheme") { continue }
return err
}
_ = res
} Defensive patterns
Strategy: validation
Validate before calling
var supportedOutboundPrefixes = []string{
"vmess://", "vless://", "trojan://", "ss://",
"hysteria2://", "hy2://", "wireguard://", "wg://",
}
func isSupportedOutboundLink(link string) bool {
for _, p := range supportedOutboundPrefixes {
if strings.HasPrefix(strings.ToLower(strings.TrimSpace(link)), p) {
return true
}
}
return false
} Try / catch
res, err := link.ParseOutbound(l)
if err != nil {
if strings.Contains(err.Error(), "unsupported link scheme") {
continue // skip foreign protocols instead of failing the batch
}
return err
} Prevention
- Trim and case-normalize links before parsing.
- Filter subscription entries to known schemes before import.
- Reject entries missing '://'.
When it happens
Trigger: Feeding ssr://, tuic://, juicity://, socks://, https:// or plain host:port strings; a link with a typo'd scheme (vles://, vmess1://); an empty/whitespace string after trimming; a link whose scheme prefix lost its slashes in copy-paste.
Common situations: Bulk-importing a subscription that mixes supported and unsupported protocols; parsing share links copied from messengers that strip '://'; older ssr-format links in Chinese provider subscriptions.
Related errors
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/d21b045fa55ac9ad.
Report an issue: GitHub.