{"record":{"id":"a930cc00eebbacdd","repo":"zed-industries/zed","slug":"connection-to-tcp-dap-timeout-address","errorCode":null,"errorMessage":"Connection to TCP DAP timeout {address}","messagePattern":"Connection to TCP DAP timeout (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dap/src/transport.rs","lineNumber":606,"sourceCode":"        })\n    }\n\n    fn connect(\n        &mut self,\n    ) -> Task<\n        Result<(\n            Box<dyn AsyncWrite + Unpin + Send + 'static>,\n            Box<dyn AsyncRead + Unpin + Send + 'static>,\n        )>,\n    > {\n        let executor = self.executor.clone();\n        let timeout = self.timeout;\n        let address = SocketAddr::new(self.host, self.port);\n        let process = self.process.clone();\n        executor.clone().spawn(async move {\n            select! {\n                _ = executor.timer(Duration::from_millis(timeout)).fuse() => {\n                    anyhow::bail!(\"Connection to TCP DAP timeout {address}\");\n                },\n                result = executor.clone().spawn(async move {\n                    loop {\n                        match TcpStream::connect(address).await {\n                            Ok(stream) => {\n                                let (read, write) = stream.split();\n                                return Ok((Box::new(write) as _, Box::new(read) as _))\n                            },\n                            Err(_) => {\n                                let has_process = process.lock().is_some();\n                                if has_process {\n                                    let status = process.lock().as_mut().unwrap().try_status();\n                                    if let Ok(Some(_)) = status {\n                                        let child = process.lock().take().unwrap();\n                                        let output = child.output().await?;\n                                        let output = if output.stderr.is_empty() {\n                                            String::from_utf8_lossy(&output.stdout).to_string()\n                                        } else {","sourceCodeStart":588,"sourceCodeEnd":624,"githubUrl":"https://github.com/zed-industries/zed/blob/f4178619acd0d47ea1f76a2025c42962c6d6638c/crates/dap/src/transport.rs#L588-L624","documentation":"In the TCP DAP transport, a select! races a timer (Duration::from_millis(self.timeout)) against a retry loop of TcpStream::connect(address); when the timer wins, this bail names the host:port that never accepted a connection. The inner loop retries connects with 100ms gaps and only exits early if the spawned process dies (see the 'exited before debugger attached' error).","triggerScenarios":"Attaching over TCP with host/port config where nothing listens: the debug server (e.g. 'debugpy -w', 'dlv --headless --listen', java agent) starts slowly and misses the window, the port is wrong or occupied by another service that rejects DAP, a firewall silently drops SYN packets so connects never complete (no RST means the loop keeps retrying until timeout).","commonSituations":"Port mismatch between adapter config and server args; server listening on 127.0.0.1 while config uses another interface; containerized debug servers not publishing the port; firewall/NAT dropping instead of refusing; timeout value too small for a slow-starting server.","solutions":["Confirm the server actually listens: `ss -ltnp | grep <port>` / `nc -vz <host> <port>`","Align host/port in the debug config with the server's --listen/--port arguments","Increase the timeout setting if the server legitimately needs longer to bind","Check firewall/NAT rules drop-vs-reject behavior between Zed and the target"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Verify the port is listening before starting the TCP transport\nlet stream = smol::net::TcpStream::connect((host, port)).await;\nanyhow::ensure!(stream.is_ok(), \"nothing listening on {host}:{port} yet\");","typeGuard":null,"tryCatchPattern":"match connect_tcp(host, port, timeout_ms).await {\n    Ok(io) => Ok(io),\n    Err(err) if err.to_string().contains(\"Connection to TCP DAP timeout\") => {\n        // check whether the spawned process died, extend timeout, or surface a port-mismatch hint\n        Err(err.context(\"verify the debug server listens on the configured host:port\"))\n    }\n    Err(err) => Err(err),\n}","preventionTips":["Derive the connect port and the server's --listen flag from one config value so they cannot diverge","Health-check the port (nc/ss) before invoking attach","Size the timeout to the slowest realistic server start, and prefer refuse-fast failures over silent drops"],"tags":["dap","tcp","timeout","connection-refused","debug-adapter","rust"],"backgroundTag":"tcp-connection-timeout","analyzedSha":"f4178619acd0d47ea1f76a2025c42962c6d6638c","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}