{"record":{"id":"d21b045fa55ac9ad","repo":"MHSanaei/3x-ui","slug":"unsupported-link-scheme","errorCode":null,"errorMessage":"unsupported link scheme","messagePattern":"unsupported link scheme","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/util/link/outbound.go","lineNumber":127,"sourceCode":"//   - hysteria2:// (also hy2://)\n//   - wireguard:// (also wg://)\nfunc ParseLink(link string) (*ParseResult, error) {\n\tlink = strings.TrimSpace(link)\n\tswitch {\n\tcase strings.HasPrefix(link, \"vmess://\"):\n\t\treturn parseVmess(link)\n\tcase strings.HasPrefix(link, \"vless://\"):\n\t\treturn parseVless(link)\n\tcase strings.HasPrefix(link, \"trojan://\"):\n\t\treturn parseTrojan(link)\n\tcase strings.HasPrefix(link, \"ss://\"):\n\t\treturn parseShadowsocks(link)\n\tcase strings.HasPrefix(link, \"hysteria2://\"), strings.HasPrefix(link, \"hy2://\"):\n\t\treturn parseHysteria2(link)\n\tcase strings.HasPrefix(link, \"wireguard://\"), strings.HasPrefix(link, \"wg://\"):\n\t\treturn parseWireguard(link)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported link scheme\")\n\t}\n}\n\n// --- vmess ---\n\nfunc parseVmess(link string) (*ParseResult, error) {\n\tb64 := strings.TrimPrefix(link, \"vmess://\")\n\t// vmess:// base64(json)\n\traw, err := base64.StdEncoding.DecodeString(padBase64(b64))\n\tif err != nil {\n\t\t// Some providers use raw URL-safe\n\t\traw, err = base64.RawURLEncoding.DecodeString(b64)\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"vmess decode: %w\", err)\n\t}\n\tvar j map[string]any\n\tif err := json.Unmarshal(raw, &j); err != nil {","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/util/link/outbound.go#L109-L145","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: aborting a whole batch on one bad link\nfor _, l := range links {\n    res, err := link.ParseOutbound(l)\n    if err != nil { return err }\n}\n\n// after: skip unparseable entries\nfor _, l := range links {\n    res, err := link.ParseOutbound(l)\n    if err != nil {\n        if strings.Contains(err.Error(), \"unsupported link scheme\") { continue }\n        return err\n    }\n    _ = res\n}","handlingStrategy":"validation","validationCode":"var supportedOutboundPrefixes = []string{\n    \"vmess://\", \"vless://\", \"trojan://\", \"ss://\",\n    \"hysteria2://\", \"hy2://\", \"wireguard://\", \"wg://\",\n}\nfunc isSupportedOutboundLink(link string) bool {\n    for _, p := range supportedOutboundPrefixes {\n        if strings.HasPrefix(strings.ToLower(strings.TrimSpace(link)), p) {\n            return true\n        }\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":"res, err := link.ParseOutbound(l)\nif err != nil {\n    if strings.Contains(err.Error(), \"unsupported link scheme\") {\n        continue // skip foreign protocols instead of failing the batch\n    }\n    return err\n}","preventionTips":["Trim and case-normalize links before parsing.","Filter subscription entries to known schemes before import.","Reject entries missing '://'."],"tags":["parsing","proxy-links","validation","outbound"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}