{"record":{"id":"d4fa5f0bbb23bf7c","repo":"openai/codex","slug":"empty-proxy-connection","errorCode":null,"errorMessage":"empty proxy connection","messagePattern":"empty proxy connection","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"warning","filePath":"codex-rs/network-proxy/src/attribution.rs","lineNumber":78,"sourceCode":"                .environment_id()\n                .is_some_and(|actual| actual != expected_environment_id)\n        {\n            return Err(io::Error::new(\n                io::ErrorKind::PermissionDenied,\n                \"network proxy attribution environment mismatch\",\n            )\n            .into());\n        }\n        stream.extensions_mut().insert(Arc::new(state));\n        self.inner.serve(stream).await.map_err(Into::into)\n    }\n}\n\nasync fn read_attribution_token(stream: &mut TcpStream) -> Result<Option<String>, BoxError> {\n    let mut marker = [0_u8; 1];\n    let read = stream.stream.peek(&mut marker).await?;\n    if read == 0 {\n        return Err(io::Error::new(io::ErrorKind::UnexpectedEof, \"empty proxy connection\").into());\n    }\n    if marker[0] != ATTRIBUTION_FRAME_MAGIC[0] {\n        return Ok(None);\n    }\n\n    let token = tokio::time::timeout(ATTRIBUTION_FRAME_TIMEOUT, async {\n        let mut magic = [0_u8; ATTRIBUTION_FRAME_MAGIC.len()];\n        stream.read_exact(&mut magic).await?;\n        if &magic != ATTRIBUTION_FRAME_MAGIC {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"invalid network proxy attribution frame\",\n            ));\n        }\n\n        let token_len = stream.read_u16().await? as usize;\n        if token_len == 0 || token_len > MAX_ATTRIBUTION_TOKEN_LEN {\n            return Err(io::Error::new(","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/network-proxy/src/attribution.rs#L60-L96","documentation":"A TCP peer connected to the proxy ingress and closed without sending a single byte: the one-byte peek in read_attribution_token returned 0 (EOF). The ingress needs at least one byte to decide whether a connection is an attributed bridge connection (first byte of the magic) or plain passthrough, so an entirely empty connection is rejected with io::ErrorKind::UnexpectedEof instead of being forwarded.","triggerScenarios":"Anything that opens a socket and immediately closes it: TCP health checks and port probes (nc -z, telnet, load-balancer checks), port scanners, or a bridge client that connects then crashes/exits before writing the preface.","commonSituations":"Pointing a generic TCP health check at the proxy port; security scanners sweeping the port; a client bug that connects 'early' and drops the socket before it has anything to write.","solutions":["If it comes from a probe or scanner, expect it -- log at debug level and move on; point real health checks at an actual health endpoint.","If it comes from your own bridge client, write the attribution frame (or the first payload byte) immediately after connect rather than dropping the socket.","Do not gate retry or startup logic on this error; it carries no recoverable state."],"exampleFix":"// before: health check connects, reads, closes -> server peeks 0 bytes\n// after: send at least one byte, or target a real health endpoint\nlet mut s = TcpStream::connect(addr).await?;\ns.write_all(b\"PING\\n\").await?;","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Peer behavior cannot be validated in advance; classify at accept time\nif let Some(e) = err.downcast_ref::<io::Error>() {\n    if e.kind() == io::ErrorKind::UnexpectedEof\n        && e.to_string().contains(\"empty proxy connection\")\n    {\n        // probe or scanner: log at debug, do not retry, do not alert\n    }\n}","preventionTips":["Aim TCP health checks at a real health endpoint, or make them send at least one byte.","In bridge clients, write the preface immediately after connect -- never connect speculatively.","Treat this error as expected noise in metrics, not as a proxy failure."],"tags":["rust","codex","network-proxy","eof","connection","probe"],"backgroundTag":"unexpected-eof","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}