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

  1. Print/trim the failing link and check its scheme against the supported list before retrying.
  2. Filter or skip unsupported entries when batch-parsing instead of aborting the whole list.
  3. Convert ssr:// or tuic:// links manually (or extend the dispatcher's prefix table if you control the fork).
  4. 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

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.