MHSanaei/3x-ui · warning

bad legacy ss hp

Error message

bad legacy ss hp

What it means

Returned by the legacy ss branch when the base64-decoded payload does contain an '@', but the host:port part after it has no ':' (LastIndex returns -1). The parser now has a host but no way to extract a port, so it refuses rather than inventing one.

Source

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

				},
			},
		}
		return &ParseResult{Outbound: ob, Identity: identity}, nil
	}
	// legacy: whole thing b64
	dec, err := base64DecodeFlexible(core)
	if err != nil {
		return nil, err
	}
	at = strings.Index(dec, "@")
	if at < 0 {
		return nil, fmt.Errorf("bad legacy ss")
	}
	userInfo := dec[:at]
	hp := dec[at+1:]
	colon := strings.LastIndex(hp, ":")
	if colon < 0 {
		return nil, fmt.Errorf("bad legacy ss hp")
	}
	host := hp[:colon]
	port, err := strconv.Atoi(hp[colon+1:])
	if err != nil {
		return nil, fmt.Errorf("bad legacy 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

View on GitHub (pinned to ad32144c42)

Solutions

  1. Decode and inspect the payload; append the missing ':port' and re-encode.
  2. Use the SIP002 form going forward — it keeps host and port in clear text and fails more obviously.
  3. Validate legacy payloads with a regexp like ^[^@]+@[^@]+:\d+$ before parsing in bulk.

Example fix

// before (payload decodes to aes-256-gcm:pass@example.com)
ss://YWVzLTI1Ni1nY206cGFzc0BleGFtcGxlLmNvbQ==

// after (port appended)
ss://YWVzLTI1Ni1nY206cGFzc0BleGFtcGxlLmNvbTo0NDM=
Defensive patterns

Strategy: validation

Validate before calling

var legacySSRe = regexp.MustCompile(`^[^@]+@[^@]+:\d{1,5}$`)
func validLegacySSPayload(link string) bool {
    core := strings.TrimPrefix(link, "ss://")
    dec, err := base64DecodeFlexible(core)
    return err == nil && legacySSRe.MatchString(dec)
}

Prevention

When it happens

Trigger: Decoded payload like 'method:pass@host' (port omitted); truncation that cut ':port'; IPv6 host without brackets so parsing logic still finds no usable colon; whitespace or encoding artifacts swallowing the tail.

Common situations: Hand-built legacy links where the port was forgotten; partially corrupted subscriptions; providers testing with dummy entries.

Related errors


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