{"record":{"id":"7281cfee7bc841a5","repo":"astrid-runtime/astrid","slug":"handshake-response-too-large-resp-len-bytes","errorCode":null,"errorMessage":"Handshake response too large: {resp_len} bytes","messagePattern":"Handshake response too large: (.+?) bytes","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-uplink/src/socket_client.rs","lineNumber":614,"sourceCode":"    tokio::time::timeout(HANDSHAKE_TIMEOUT, async {\n        stream.write_all(&len.to_be_bytes()).await?;\n        stream.write_all(&request_bytes).await?;\n        stream.flush().await?;\n        Ok::<(), std::io::Error>(())\n    })\n    .await\n    .context(\"Handshake request write timed out\")?\n    .context(\"Failed to send handshake request\")?;\n\n    let mut len_buf = [0u8; 4];\n    tokio::time::timeout(HANDSHAKE_TIMEOUT, stream.read_exact(&mut len_buf))\n        .await\n        .context(\"Handshake response timed out\")?\n        .context(\"Failed to read handshake response length\")?;\n\n    let resp_len = u32::from_be_bytes(len_buf) as usize;\n    if resp_len > MAX_HANDSHAKE_RESPONSE_SIZE {\n        anyhow::bail!(\"Handshake response too large: {resp_len} bytes\");\n    }\n\n    let mut resp_payload = vec![0u8; resp_len];\n    tokio::time::timeout(HANDSHAKE_TIMEOUT, stream.read_exact(&mut resp_payload))\n        .await\n        .context(\"Handshake response payload timed out\")?\n        .context(\"Failed to read handshake response payload\")?;\n\n    serde_json::from_slice(&resp_payload).context(\"Failed to parse handshake response\")\n}\n","sourceCodeStart":596,"sourceCodeEnd":625,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-uplink/src/socket_client.rs#L596-L625","documentation":"send_request_read_response reads the handshake response's 4-byte length prefix and rejects any declared size above MAX_HANDSHAKE_RESPONSE_SIZE before allocating and reading the payload. Handshake responses are small by protocol; an oversized prefix indicates corruption, desync, or a hostile peer, so it fails fast.","triggerScenarios":"Calling send_request_read_response (via perform_handshake_in_home) when the response length prefix exceeds MAX_HANDSHAKE_RESPONSE_SIZE — e.g. the peer wrote raw payload without framing, the stream is misaligned after a failed write, or a garbage/broken response arrives.","commonSituations":"Handshake request was malformed so the daemon's error output (e.g. an HTML/log blob) is misread as a framed response; socket desynchronization from a previous oversized write; incompatible daemon version framing the response differently.","solutions":["Reconnect and retry the handshake to restore a clean stream state.","Verify the request written before the read was correctly framed (length-prefixed); a bad request can corrupt the response stream.","Align client and daemon versions so both use the same handshake framing and MAX_HANDSHAKE_RESPONSE_SIZE.","If responses legitimately grew beyond the cap, raise MAX_HANDSHAKE_RESPONSE_SIZE on both sides."],"exampleFix":"// before: writing the request without its length prefix desyncs the response framing\nstream.write_all(&request_payload).await?;\n// after\nlet mut framed = Vec::with_capacity(4 + request_payload.len());\nframed.extend_from_slice(&(request_payload.len() as u32).to_be_bytes());\nframed.extend_from_slice(&request_payload);\nstream.write_all(&framed).await?;","handlingStrategy":"try-catch","validationCode":"// Sanity-bound the request you send; a corrupt request can corrupt the response stream\nif request_payload.len() > MAX_HANDSHAKE_REQUEST_SIZE {\n    return Err(anyhow::anyhow!(\"handshake request too large\"));\n}","typeGuard":null,"tryCatchPattern":"match perform_handshake_in_home(&socket_path).await {\n    Ok(auth) => auth,\n    Err(e) if e.to_string().contains(\"Handshake response too large\") => {\n        // framing desynced: reconnect and retry once with a clean stream\n        let mut client = reconnect(&socket_path).await?;\n        perform_handshake_on(&mut client).await\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always write length-prefixed requests so response framing stays aligned.","Keep MAX_HANDSHAKE_RESPONSE_SIZE consistent on both ends of the protocol.","Reconnect rather than continue reading once the stream is suspect.","Add a protocol test asserting response sizes stay under the cap."],"tags":["handshake","protocol","size-limit","ipc"],"backgroundTag":"payload-too-large","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}