{"record":{"id":"e1011cc5a263ffe4","repo":"cloudflare/quiche","slug":"initial-send-failed-e1011c","errorCode":null,"errorMessage":"initial send failed","messagePattern":"initial send failed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"h3i/src/client/sync_client.rs","lineNumber":219,"sourceCode":"    if let Some(session) = &args.session {\n        conn.set_session(session)\n            .map_err(|error| ClientError::Other(error.to_string()))?;\n    }\n\n    if let Some(keylog) = &mut keylog {\n        if let Ok(keylog) = keylog.try_clone() {\n            conn.set_keylog(Box::new(keylog));\n        }\n    }\n\n    log::info!(\n        \"connecting to {peer_addr:} from {local_addr:} with scid {scid:?}\",\n    );\n\n    let mut app_proto_selected = false;\n\n    // Send ClientHello and initiate the handshake.\n    let (write, send_info) = conn.send(&mut out).expect(\"initial send failed\");\n\n    let mut client = SyncClient::new(close_trigger_frames);\n    // Send early data if connection is_in_early_data (resumption with 0-RTT was\n    // successful) and if we have early_actions.\n    if conn.is_in_early_data() {\n        if let Some(early_actions) = early_actions {\n            let mut early_action_iter = early_actions.iter();\n            let mut wait_duration = None;\n            let mut wait_instant = None;\n            let mut waiting_for = WaitingFor::default();\n\n            check_duration_and_do_actions(\n                &mut wait_duration,\n                &mut wait_instant,\n                &mut early_action_iter,\n                &mut conn,\n                &mut waiting_for,\n                client.stream_parsers_mut(),","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/cloudflare/quiche/blob/9f96daa2c22a4468b0036fb0a0a3894eee6498b8/h3i/src/client/sync_client.rs#L201-L237","documentation":"connect_with_early_data calls conn.send() to emit the ClientHello and panics if the initial packet write fails. conn.send() returns Err when there is nothing to send or the connection is in a state that cannot emit packets (e.g. already closed/drained, or internal crypto failure building the initial packet).","triggerScenarios":"The connection is done/drained before the first send, TLS setup failed so no ClientHello can be built, or the output buffer is too small/misallocated.","commonSituations":"Reusing a closed quiche::Connection; invalid TLS configuration (bad ALPN/CA setup) during client creation; extremely small send buffer in custom code paths.","solutions":["Ensure the connection is freshly created and not closed before connect_with_early_data is called.","Verify TLS/ALPN configuration on the quiche::Config is valid.","Replace the expect with proper error handling and retry or reconnect logic."],"exampleFix":"// before\nlet (write, send_info) = conn.send(&mut out).expect(\"initial send failed\");\n// after\nlet (write, send_info) = conn.send(&mut out)\n    .map_err(|e| ClientError::Connect(format!(\"initial send failed: {e}\")))?;","handlingStrategy":"try-catch","validationCode":"if conn.is_closed() || conn.is_draining() {\n    return Err(ClientError::Connect(\"connection already closed\".into()));\n}","typeGuard":null,"tryCatchPattern":"match conn.send(&mut out) {\n    Ok((w, info)) => (w, info),\n    Err(e) => return Err(ClientError::Connect(format!(\"initial send failed: {e}\"))),\n}","preventionTips":["Always use a freshly-created connection for connect().","Verify TLS/ALPN config before connecting.","Handle quiche errors instead of expect()ing in library-adjacent code."],"tags":["quic","tls","handshake","panic"],"backgroundTag":"http-request-failed","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"}