{"record":{"id":"8e94a6bca66f22bb","repo":"chenhg5/cc-connect","slug":"providerproxy-listen-w","errorCode":null,"errorMessage":"providerproxy: listen: %w","messagePattern":"providerproxy: listen: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/providerproxy.go","lineNumber":44,"sourceCode":"\tthinkingOverride string\n\tlistener         net.Listener\n\tserver           *http.Server\n\tonce             sync.Once\n}\n\n// NewProviderProxy creates and starts a local reverse proxy for the\n// given upstream URL. thinkingOverride controls what thinking.type to\n// rewrite \"adaptive\" to (e.g. \"disabled\" or \"enabled\").\n// Returns the local URL to use as ANTHROPIC_BASE_URL.\nfunc NewProviderProxy(targetURL, thinkingOverride string) (*ProviderProxy, string, error) {\n\ttarget, err := url.Parse(strings.TrimRight(targetURL, \"/\"))\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"providerproxy: parse target: %w\", err)\n\t}\n\n\tlistener, err := net.Listen(\"tcp\", \"127.0.0.1:0\")\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"providerproxy: listen: %w\", err)\n\t}\n\n\tproxy := httputil.NewSingleHostReverseProxy(target)\n\torigDirector := proxy.Director\n\tproxy.Director = func(req *http.Request) {\n\t\torigDirector(req)\n\t\treq.Host = target.Host\n\t}\n\tproxy.FlushInterval = -1 // flush SSE events immediately\n\n\toverride := thinkingOverride\n\tmux := http.NewServeMux()\n\tmux.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.Method == http.MethodPost && strings.HasSuffix(r.URL.Path, \"/messages\") {\n\t\t\trewriteThinkingInRequest(r, override)\n\t\t}\n\t\tproxy.ServeHTTP(w, r)\n\t})","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/providerproxy.go#L26-L62","documentation":"After parsing the target, `NewProviderProxy` binds a local listener on `127.0.0.1:0` (an ephemeral port). If `net.Listen` fails it returns `providerproxy: listen: %w`. Binding to an OS-chosen port on loopback should virtually never fail; failure indicates a serious system-level networking problem.","triggerScenarios":"Calling NewProviderProxy when the OS refuses to open a loopback TCP socket: exhausted ephemeral port range / file-descriptor limit, socket creation denied by sandbox/seccomp policy, or networking stack unavailable.","commonSituations":"Container with a very low RLIMIT_NOFILE and thousands of open connections; hardened sandbox (gVisor, restricted Docker) forbidding socket creation; host with `net.ipv4.ip_local_port_range` exhausted by leaked sockets.","solutions":["Check the underlying wrapped error; `EMFILE`/`ENFILE` means raise the file-descriptor limit (`ulimit -n`).","If running in a sandbox/container, grant permission to create TCP sockets on loopback.","Audit for socket/fd leaks in the process (`lsof -p <pid>`) and fix the leak.","Retry after other connections close if the port range is temporarily exhausted."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"proxy, local, err := NewProviderProxy(target, thinking)\nif err != nil {\n    slog.Error(\"provider proxy start failed\", \"error\", err) // inspect wrapped net.OpError (EMFILE, EPERM, ...)\n    return err\n}","preventionTips":["Raise RLIMIT_NOFILE in containers/daemons that open many sockets.","Avoid sandboxes that block loopback socket creation for the process.","Audit for fd/socket leaks with lsof in long-running daemons.","Check the wrapped errno to distinguish permission vs exhaustion."],"tags":["network","listen","proxy","go","os"],"backgroundTag":"connection-refused","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}