{"record":{"id":"233f5ba8b805324b","repo":"astrid-runtime/astrid","slug":"mount-callback-frame-exceeds-limit","errorCode":null,"errorMessage":"mount callback frame exceeds limit","messagePattern":"mount callback frame exceeds limit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/storage_mount.rs","lineNumber":576,"sourceCode":"        };\n        let response = dispatch_request(&kernel, &state, request).await;\n        if write_response(&mut stream, response).await.is_err() {\n            return;\n        }\n    }\n}\n\n#[cfg(any(unix, windows))]\nasync fn read_request(stream: &mut LocalStream) -> Result<Option<CallbackRequest>, io::Error> {\n    let mut length = [0_u8; 4];\n    match stream.read_exact(&mut length).await {\n        Ok(_) => {},\n        Err(error) if error.kind() == io::ErrorKind::UnexpectedEof => return Ok(None),\n        Err(error) => return Err(error),\n    }\n    let length = u32::from_be_bytes(length) as usize;\n    if length > MAX_CALLBACK_FRAME_BYTES {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            \"mount callback frame exceeds limit\",\n        ));\n    }\n    let mut bytes = vec![0_u8; length];\n    stream.read_exact(&mut bytes).await?;\n    let protocol = serde_json::from_slice::<ProtocolProbe>(&bytes)\n        .map_err(io::Error::other)?\n        .protocol_version;\n    if protocol == STORAGE_FILESYSTEM_PROTOCOL_V2 {\n        let request = serde_json::from_slice::<StorageFilesystemRequestV2>(&bytes)\n            .map_err(io::Error::other)?;\n        let operation = decode_operation_v2(request.operation)?;\n        Ok(Some(CallbackRequest {\n            request: StorageFilesystemRequestV1 {\n                protocol_version: STORAGE_FILESYSTEM_PROTOCOL_V1,\n                request_id: request.request_id,\n                lease_token: request.lease_token,","sourceCodeStart":558,"sourceCodeEnd":594,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/storage_mount.rs#L558-L594","documentation":"The mount IPC callback protocol frames each request with a big-endian u32 length; a frame declaring a length above MAX_CALLBACK_FRAME_BYTES is rejected before any body is read. This prevents a malformed or malicious peer from making the server allocate an unbounded buffer.","triggerScenarios":"`read_request` (called by `handle_connection`) reads the 4-byte length prefix, converts it to usize, and finds `length > MAX_CALLBACK_FRAME_BYTES`. Caused by protocol desync (garbage bytes interpreted as a length), a buggy/incompatible client version, or a corrupted stream.","commonSituations":"Mixing client and server versions with different framing; connecting a wrong process/socket to the mount callback port; binary garbage after an earlier partial read desynchronized framing.","solutions":["Ensure the client and server are the same version so both agree on frame limits and framing","Restart both ends of the mount connection to resynchronize the stream","Check what is actually connecting to the callback socket — reject/fix rogue or wrong clients","If limits legitimately changed, raise MAX_CALLBACK_FRAME_BYTES consistently on both sides"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// client side: check the frame before writing it\nif payload.len() > MAX_CALLBACK_FRAME_BYTES {\n    return Err(\"callback frame too large; split or reject\");\n}","typeGuard":null,"tryCatchPattern":"match err.downcast_ref::<io::Error>() {\n    Some(e) if e.kind() == io::ErrorKind::InvalidData && msg.contains(\"frame exceeds limit\") => {\n        // resynchronize: drop the connection and reconnect with matching framing\n        reconnect_mount()?;\n    }\n    _ => return Err(err),\n}","preventionTips":["Keep client and server versions in lockstep for the callback protocol","Only connect the intended client to the callback socket","Cap your own request payloads well under MAX_CALLBACK_FRAME_BYTES"],"tags":["ipc","protocol","limit"],"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"}