{"record":{"id":"45a1a78d630505b1","repo":"MHSanaei/3x-ui","slug":"bad-legacy-ss","errorCode":null,"errorMessage":"bad legacy ss","messagePattern":"bad legacy ss","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/util/link/outbound.go","lineNumber":392,"sourceCode":"\t\tob := Outbound{\n\t\t\t\"protocol\": \"shadowsocks\",\n\t\t\t\"tag\":      remark,\n\t\t\t\"settings\": map[string]any{\n\t\t\t\t\"servers\": []any{\n\t\t\t\t\tmap[string]any{\"address\": host, \"port\": port, \"password\": pass, \"method\": method},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\treturn &ParseResult{Outbound: ob, Identity: identity}, nil\n\t}\n\t// legacy: whole thing b64\n\tdec, err := base64DecodeFlexible(core)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tat = strings.Index(dec, \"@\")\n\tif at < 0 {\n\t\treturn nil, fmt.Errorf(\"bad legacy ss\")\n\t}\n\tuserInfo := dec[:at]\n\thp := dec[at+1:]\n\tcolon := strings.LastIndex(hp, \":\")\n\tif colon < 0 {\n\t\treturn nil, fmt.Errorf(\"bad legacy ss hp\")\n\t}\n\thost := hp[:colon]\n\tport, err := strconv.Atoi(hp[colon+1:])\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"bad legacy ss port %q: %w\", hp[colon+1:], err)\n\t}\n\tmethod, pass := splitMethodPass(userInfo)\n\tidentity := \"ss:\" + method + \":\" + pass + \"@\" + host + \":\" + strconv.Itoa(port)\n\tob := Outbound{\n\t\t\"protocol\": \"shadowsocks\",\n\t\t\"tag\":      remark,\n\t\t\"settings\": map[string]any{","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/util/link/outbound.go#L374-L410","documentation":"Returned by parseShadowsocks' legacy branch: the whole ss:// payload (after the scheme) was base64-decoded successfully, but the decoded string contains no '@' separating userinfo from host:port. Legacy format is base64('method:pass@host:port'), so a missing '@' means the decoded text is not a legacy ss link at all.","triggerScenarios":"A ss:// link that is actually SIP002 with empty userinfo (ss://@host:port style reaching the wrong branch); payload decoding to plain JSON or free text; truncated base64 that still decodes to garbage without '@'; a remark-only payload.","commonSituations":"Old subscription formats mixing ssr-style and ss-style encodings; links where only the userinfo was base64'd but the branch decided otherwise; hand-crafted legacy links missing the userinfo separator.","solutions":["Base64-decode the payload yourself and inspect it — it must read method:password@host:port.","If the link is SIP002 (has a literal '@' before base64-only userinfo), keep the '@' unencoded: ss://BASE64USER@host:port.","Regenerate the link with a current client (SIP002 is the modern form).","Drop broken entries when batch-importing instead of retrying them."],"exampleFix":"// before (decoded payload has no '@')\nss://cG9ydDQ0Mw==\n\n// after (legacy form: base64 of method:pass@host:port)\nss://YWVzLTI1Ni1nY206cGFzc0BleGFtcGxlLmNvbTo0NDM=","handlingStrategy":"validation","validationCode":"func looksLikeLegacySS(link string) bool {\n    core := strings.TrimPrefix(strings.SplitN(link, \"#\", 2)[0], \"ss://\")\n    if strings.Contains(core, \"@\") { return false } // SIP002 form\n    dec, err := base64.RawURLEncoding.DecodeString(strings.TrimRight(core, \"=\"))\n    if err != nil { dec, err = base64.StdEncoding.DecodeString(padBase64(core)) }\n    return err == nil && strings.Contains(string(dec), \"@\")\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"bad legacy ss\") {\n    // decoded payload lacked '@': not a legacy ss link — decode it and inspect, then skip or fix\n}","preventionTips":["Prefer SIP002 (ss://BASE64USER@host:port) over legacy whole-payload base64.","When generating legacy links, encode exactly method:password@host:port.","Skip undecodable entries when batch-importing."],"tags":["parsing","proxy-links","shadowsocks","legacy","base64"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}