{"record":{"id":"095588e64bd15154","repo":"XTLS/Xray-core","slug":"failed-to-find-the-default-path-config","errorCode":null,"errorMessage":"failed to find the default \"path\" config","messagePattern":"failed to find the default \"path\" config","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"proxy/trojan/server.go","lineNumber":447,"sourceCode":"\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif k == '?' || k == ' ' {\n\t\t\t\t\t\t\tpath = string(firstBytes[i:j])\n\t\t\t\t\t\t\terrors.LogInfo(ctx, \"realPath = \"+path)\n\t\t\t\t\t\t\tif pfb[path] == nil {\n\t\t\t\t\t\t\t\tpath = \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfb := pfb[path]\n\tif fb == nil {\n\t\treturn errors.New(`failed to find the default \"path\" config`).AtWarning()\n\t}\n\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)\n\tctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)\n\n\tvar conn net.Conn\n\tif err := retry.ExponentialBackoff(5, 100).On(func() error {\n\t\tvar dialer net.Dialer\n\t\tconn, err = dialer.DialContext(ctx, fb.Type, fb.Dest)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}); err != nil {\n\t\treturn errors.New(\"failed to dial to \" + fb.Dest).Base(err).AtWarning()\n\t}\n\tdefer conn.Close()","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/trojan/server.go#L429-L465","documentation":"The name+alpn fallback group contains path-specific entries but no empty-path default: lookup pfb[path] missed (path sniffed from the HTTP request line) and pfb[\"\"] is nil. Path sniffing only runs when the first bytes look like an HTTP method and are not h2c.","triggerScenarios":"Multiple path-based fallbacks are configured for this name/alpn, the client's HTTP path does not equal any configured 'path', and no pathless default entry exists in the same group.","commonSituations":"WebSocket/gRPC fallback paths mistyped (missing leading slash, different case), path-based routing added without a catch-all, or a non-HTTP client sending bytes that accidentally parse into an unmatched path.","solutions":["Add an entry with no 'path' under the same name/alpn as the universal default","Compare the logged sniffed path with the configured paths character by character","Keep path strings exactly as the client requests them, including the leading '/'"],"exampleFix":"// json: last entry is the pathless default\n\"fallbacks\": [\n  {\"name\": \"ws.example.com\", \"path\": \"/ws\", \"dest\": 9000},\n  {\"name\": \"ws.example.com\", \"dest\": 8080}\n]","handlingStrategy":"validation","validationCode":"// ensure path-based groups keep a pathless default\nfunc validatePaths(fbs []Fallback) error {\n    type key struct{ name, alpn string }\n    defaults := map[key]bool{}\n    for _, f := range fbs {\n        k := key{f.Name, f.Alpn}\n        if f.Path == \"\" { defaults[k] = true }\n    }\n    for _, f := range fbs {\n        if f.Path != \"\" && !defaults[key{f.Name, f.Alpn}] {\n            return errors.New(\"path fallbacks under '\" + f.Name + \"' lack a pathless default\")\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Every group with path entries needs one pathless entry as fallback-of-last-resort","Write paths exactly as clients request them, with the leading slash","Prefer dest-based routing over deep path-based routing unless required by WS/gRPC backends"],"tags":["trojan","fallback","path","config"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}