{"record":{"id":"eec94fef0f2f5e03","repo":"astrid-runtime/astrid","slug":"ipc-frame-too-large-len-bytes","errorCode":null,"errorMessage":"IPC frame too large: {len} bytes","messagePattern":"IPC frame too large: (.+?) bytes","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-uplink/src/native/framing.rs","lineNumber":36,"sourceCode":"        }\n    }\n\n    /// Read one length-prefixed message while retaining partial frame state.\n    ///\n    /// `AsyncReadExt::read` is cancellation-safe, and all bytes returned by a\n    /// completed read are appended before the next await. Recreating this\n    /// future after another `select!` branch wins therefore cannot discard a\n    /// partially received prefix or body.\n    pub(super) async fn read_message(&mut self) -> std::io::Result<Option<IpcMessage>> {\n        loop {\n            if self.buffered.len() >= 4 {\n                let len = u32::from_be_bytes(\n                    self.buffered[..4]\n                        .try_into()\n                        .expect(\"four-byte frame prefix\"),\n                ) as usize;\n                if len > MAX_FRAME_BYTES {\n                    return Err(std::io::Error::new(\n                        std::io::ErrorKind::InvalidData,\n                        format!(\"IPC frame too large: {len} bytes\"),\n                    ));\n                }\n                let frame_len = 4_usize.checked_add(len).ok_or_else(|| {\n                    std::io::Error::new(std::io::ErrorKind::InvalidData, \"IPC frame overflow\")\n                })?;\n                if self.buffered.len() >= frame_len {\n                    let message =\n                        serde_json::from_slice(&self.buffered[4..frame_len]).map_err(|error| {\n                            std::io::Error::new(\n                                std::io::ErrorKind::InvalidData,\n                                format!(\"invalid IPC message: {error}\"),\n                            )\n                        })?;\n                    self.buffered.drain(..frame_len);\n                    return Ok(Some(message));\n                }","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-uplink/src/native/framing.rs#L18-L54","documentation":"The IPC framing reader reads a 4-byte big-endian length prefix and rejects any frame whose payload length exceeds MAX_FRAME_BYTES, returning InvalidData. This prevents a corrupt or hostile peer from causing an unbounded memory allocation for a single message.","triggerScenarios":"read_message encounters a length prefix whose decoded value is greater than MAX_FRAME_BYTES — the peer sent a larger-than-allowed frame, the stream is misaligned (reading payload bytes as a length), or sender and receiver use different MAX_FRAME_BYTES limits.","commonSituations":"Desynchronized stream after a partial read or a skipped byte (everything after reads as garbage lengths); peer library version with a larger frame limit; protocol misuse such as writing raw bytes without the length prefix; corrupted transport (pipe/socket) flipping length bytes.","solutions":["Resynchronize the stream (discard the connection and reconnect) — once misaligned, every subsequent frame fails.","Ensure the peer respects the same MAX_FRAME_BYTES limit; chunk oversized messages on the sender side.","Verify the sender always writes the 4-byte big-endian length prefix before each payload (use the library's write path, not raw I/O).","Check the transport for corruption/truncation; add an outer integrity check if the channel is unreliable."],"exampleFix":"// before\nstream.write_all(&big_payload).await?; // no prefix / oversized\n// after\nfor chunk in big_payload.chunks(MAX_FRAME_BYTES) {\n    framed.write_message(chunk).await?; // library framing, within limit\n}","handlingStrategy":"try-catch","validationCode":"// before sending: enforce the frame limit on the sender side\nif payload.len() > MAX_FRAME_BYTES {\n    return Err(\"payload must be chunked to fit MAX_FRAME_BYTES\");\n}","typeGuard":null,"tryCatchPattern":"match framed.read_message().await {\n    Err(e) if e.kind() == io::ErrorKind::InvalidData && e.to_string().contains(\"IPC frame too large\") => {\n        // framing desynced or peer violates the limit: drop and re-establish the connection\n        connection.reset().await?;\n    }\n    other => other?,\n}","preventionTips":["Keep MAX_FRAME_BYTES identical on both peers and negotiate it at handshake.","Always send via the library's framed writer, never raw I/O without the 4-byte prefix.","Chunk oversized messages before sending.","Treat any frame-size error as fatal to the stream: reconnect rather than continue reading."],"tags":["ipc","framing","protocol","limits"],"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-14T05:17:10.506Z"}