{"record":{"id":"871b9e2753fa1b10","repo":"cloudflare/quiche","slug":"timedout","errorCode":"TimedOut","errorMessage":"connection {scid:?} timed out","messagePattern":"connection (.+?) timed out","errorType":"error_code","errorClass":"io::Error","httpStatus":null,"severity":"warning","filePath":"tokio-quiche/src/quic/router/connector.rs","lineNumber":191,"sourceCode":"            self.timeout_queue.remove(&key);\n        }\n\n        let scid = conn.source_id();\n        if conn.is_established() {\n            log::debug!(\"QUIC connection established\"; \"scid\" => ?scid);\n\n            Ok(Some(NewConnection {\n                conn,\n                pending_cid: None,\n                initial_pkt: None,\n                cid_generator: None,\n                handshake_start_time,\n            }))\n        } else if conn.is_closed() {\n            let scid = conn.source_id();\n            log::error!(\"QUIC connection closed on_incoming\"; \"scid\" => ?scid);\n\n            Err(io::Error::new(\n                io::ErrorKind::TimedOut,\n                format!(\"connection {scid:?} timed out\"),\n            ))\n        } else {\n            self.set_connection_to_pending(conn).map(|()| None)\n        }\n    }\n\n    /// [`ClientConnector::on_timeout`] runs [`quiche::Connection::on_timeout`]\n    /// for a pending connection. If the connection is closed, this sends an\n    /// error upstream.\n    fn on_timeout(&mut self, scid: ConnectionId<'static>) -> io::Result<()> {\n        log::debug!(\"connection timedout\"; \"scid\" => ?scid);\n\n        let Some(mut pending) =\n            self.connection.take_if_pending_and_id_matches(&scid)\n        else {\n            log::debug!(\"timedout connection missing from pending map\"; \"scid\" => ?scid);","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/cloudflare/quiche/blob/9f96daa2c22a4468b0036fb0a0a3894eee6498b8/tokio-quiche/src/quic/router/connector.rs#L173-L209","documentation":"When tokio-quiche's connection router accepts a new incoming connection (on_incoming), a connection that has already fully closed (never completed its handshake) is reported as TimedOut with the connection's SCID. A closed-before-handshake connection is treated as a handshake timeout.","triggerScenarios":"An incoming QUIC initial that gets closed before the handshake completes — conn.is_closed() is true at on_incoming time, called from handle_initials.","commonSituations":"Clients sending malformed or stale initials; idle/dead clients probing the server; version-negotiation failures; load balancer health checks that open and abort connections.","solutions":["Inspect server logs for the SCID to correlate with the offending client","Check client QUIC version and initial packet validity","If this happens en masse, review timeouts (max_idle_timeout) and any middleboxes dropping handshake packets","Treat occasional occurrences as normal Internet noise"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match router.handle_initials(...).await {\n    Err(e) if e.kind() == io::ErrorKind::TimedOut => {\n        log::warn!(\"handshake closed before completing: {e}\"); // expected client churn\n    }\n    other => other?,\n}","preventionTips":["Monitor the rate of these errors; occasional ones are normal Internet traffic","Tune handshake timeouts and max_idle_timeout for slow clients","Log the SCID to correlate with client-side traces"],"tags":["quic","handshake","timeout","tokio-quiche"],"backgroundTag":"request-timeout","analyzedSha":"9f96daa2c22a4468b0036fb0a0a3894eee6498b8","analyzedAt":"2026-09-08T11:27:09.536Z","contentChangedAt":"2026-09-08T11:27:09.536Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}