{"record":{"id":"8c960b17940d73f0","repo":"XTLS/Xray-core","slug":"failed-to-find-the-default-alpn-config","errorCode":null,"errorMessage":"failed to find the default \"alpn\" config","messagePattern":"failed to find the default \"alpn\" config","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"proxy/trojan/server.go","lineNumber":413,"sourceCode":"\t\t\t}\n\t\t\tname = match\n\t\t}\n\t}\n\n\tif napfb[name] == nil {\n\t\tname = \"\"\n\t}\n\tapfb := napfb[name]\n\tif apfb == nil {\n\t\treturn errors.New(`failed to find the default \"name\" config`).AtWarning()\n\t}\n\n\tif apfb[alpn] == nil {\n\t\talpn = \"\"\n\t}\n\tpfb := apfb[alpn]\n\tif pfb == nil {\n\t\treturn errors.New(`failed to find the default \"alpn\" config`).AtWarning()\n\t}\n\n\tpath := \"\"\n\tif len(pfb) > 1 || pfb[\"\"] == nil {\n\t\tif firstLen >= 18 && first.Byte(4) != '*' { // not h2c\n\t\t\tfirstBytes := first.Bytes()\n\t\t\tfor i := 4; i <= 8; i++ { // 5 -> 9\n\t\t\t\tif firstBytes[i] == '/' && firstBytes[i-1] == ' ' {\n\t\t\t\t\tsearch := len(firstBytes)\n\t\t\t\t\tif search > 64 {\n\t\t\t\t\t\tsearch = 64 // up to about 60\n\t\t\t\t\t}\n\t\t\t\t\tfor j := i + 1; j < search; j++ {\n\t\t\t\t\t\tk := firstBytes[j]\n\t\t\t\t\t\tif k == '\\r' || k == '\\n' { // avoid logging \\r or \\n\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif k == '?' || k == ' ' {","sourceCodeStart":395,"sourceCodeEnd":431,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/trojan/server.go#L395-L431","documentation":"The selected fallback 'name' group has no entry for the negotiated ALPN, and it also lacks an entry with empty ALPN to fall back to. Fallback lookup is nested map[name][alpn][path]; this error means the second level has no default.","triggerScenarios":"TLS was negotiated with an ALPN string (e.g. 'h2') while every fallback under this name specifies a different alpn value, and none has alpn \"\" (wildcard).","commonSituations":"Client negotiates h2 but fallbacks were written for http/1.1 only; ALPN strings mismatch exactly (trailing space, case); xtls-rprx-vision style ALPN configured on the client forcing an unexpected value.","solutions":["Add a fallback entry with no 'alpn' key (empty = any ALPN) under the same name","Or explicitly add an entry matching the ALPN you see in logs (commonly h2 and http/1.1)","If you do not want ALPN-based splitting, strip 'alpn' from all fallback entries"],"exampleFix":"// json: second entry covers any ALPN for this name\n\"fallbacks\": [\n  {\"name\": \"a.example.com\", \"alpn\": \"h2\", \"dest\": 8001},\n  {\"name\": \"a.example.com\", \"dest\": 8001}\n]","handlingStrategy":"validation","validationCode":"// ensure each named fallback group has an alpn wildcard\nfunc validateAlpn(fbs []Fallback) error {\n    byName := map[string]bool{}\n    for _, f := range fbs {\n        if f.Name != \"\" && f.Alpn == \"\" { byName[f.Name] = true }\n    }\n    for _, f := range fbs {\n        if f.Name != \"\" && f.Alpn != \"\" && !byName[f.Name] {\n            return errors.New(\"name '\" + f.Name + \"' lacks an any-ALPN default\")\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Mirror production ALPNs explicitly (h2 + http/1.1) plus an empty-alpn default","Verify the client's ALPN list in TLS debug logs when splitting by alpn","Avoid alpn-based fallback splits unless you actually run h2-aware backends"],"tags":["trojan","fallback","alpn","config"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}