MHSanaei/3x-ui · warning

bad ss port %q: %w

Error message

bad ss port %q: %w

What it means

Returned by parseShadowsocks (SIP002 branch) when the host part contains a colon, so parsing proceeds, but everything after the last colon is not a valid integer port (strconv.Atoi fails). The offending text is quoted in the message. Note the code already trimmed trailing '/', so a lone trailing slash is not the cause — the port segment itself is non-numeric.

Source

Thrown at internal/util/link/outbound.go:370

		userB64 := core[:at]
		hp := strings.TrimRight(core[at+1:], "/")
		userInfo, err := base64DecodeFlexible(userB64)
		if err != nil {
			// SIP022 (2022-blake3-*) userinfo is percent-encoded, not base64.
			if dec, uerr := url.QueryUnescape(userB64); uerr == nil {
				userInfo = dec
			} else {
				userInfo = userB64 // not b64, rare
			}
		}
		colon := strings.LastIndex(hp, ":")
		if colon < 0 {
			return nil, fmt.Errorf("bad ss host:port")
		}
		host := hp[:colon]
		port, err := strconv.Atoi(hp[colon+1:])
		if err != nil {
			return nil, fmt.Errorf("bad ss port %q: %w", hp[colon+1:], err)
		}
		method, pass := splitMethodPass(userInfo)
		identity := "ss:" + method + ":" + pass + "@" + host + ":" + strconv.Itoa(port)
		ob := Outbound{
			"protocol": "shadowsocks",
			"tag":      remark,
			"settings": map[string]any{
				"servers": []any{
					map[string]any{"address": host, "port": port, "password": pass, "method": method},
				},
			},
		}
		return &ParseResult{Outbound: ob, Identity: identity}, nil
	}
	// legacy: whole thing b64
	dec, err := base64DecodeFlexible(core)
	if err != nil {
		return nil, err

View on GitHub (pinned to ad32144c42)

Solutions

  1. Look at the quoted value in the error — it shows exactly what the parser tried to read as the port.
  2. Move anything after the port into the fragment: ss://...@host:443#remark, and plugin params into query ?plugin=...
  3. Use a numeric port only (1-65535).
  4. Bracket IPv6 hosts: [2001:db8::1]:443.

Example fix

// before
ss://YWVzLTI1Ni1nY206cGFzcw==@example.com:https

// after
ss://YWVzLTI1Ni1nY206cGFzcw==@example.com:443
Defensive patterns

Strategy: validation

Validate before calling

// reject ss links whose port segment is non-numeric BEFORE parsing
u, err := url.Parse(link)
if err == nil && u.Scheme == "ss" {
    if p := u.Port(); p == "" { return errors.New("missing or non-numeric ss port") }
}

Try / catch

if err != nil && strings.Contains(err.Error(), "bad ss port") {
    // the message quotes the bad text: fix the link's port segment and retry
}

Prevention

When it happens

Trigger: Port spelled as a service name ('https') or empty ('host:'); path/query text left inside the port segment ('host:443?obfs=xxx' or 'host:443/'); IPv6 without brackets making 'g.cm' the port; a remark appended with ':' instead of '#'.

Common situations: Providers appending plugin parameters in non-standard positions; users writing ss://user@host:https; copy-paste where the '#remark' turned into ':remark'.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/358fcb91a0eea9b1. Report an issue: GitHub.