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, errView on GitHub (pinned to ad32144c42)
Solutions
- Look at the quoted value in the error — it shows exactly what the parser tried to read as the port.
- Move anything after the port into the fragment: ss://...@host:443#remark, and plugin params into query ?plugin=...
- Use a numeric port only (1-65535).
- 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
- Keep remarks in the # fragment and plugin params in the query string.
- Use numeric ports 1-65535 only.
- Never concatenate extra ':'-separated fields after the port.
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.