{"record":{"id":"a82e778c738f467c","repo":"astrid-runtime/astrid","slug":"fskit-callback-response-exceeds-the-bounded-frame","errorCode":null,"errorMessage":"FSKit callback response exceeds the bounded frame size","messagePattern":"FSKit callback response exceeds the bounded frame size","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-fskit/src/service.rs","lineNumber":247,"sourceCode":"    stream.flush().await?;\n    let response = read_callback_response(&mut stream).await?;\n    if response.request_id != request.request_id {\n        bail!(\"FSKit callback probe correlation mismatch\");\n    }\n    match response.outcome {\n        StorageFilesystemOutcomeV2::Success(_) => Ok(()),\n        StorageFilesystemOutcomeV2::Failure(StorageFilesystemFailureV1 { code, message }) => {\n            bail!(\"FSKit callback probe failed [{code}]: {message}\")\n        },\n    }\n}\n\nasync fn read_callback_response(stream: &mut LocalStream) -> Result<StorageFilesystemResponseV2> {\n    let mut length = [0_u8; 4];\n    stream.read_exact(&mut length).await?;\n    let length = u32::from_be_bytes(length) as usize;\n    if length == 0 || length > MAX_CALLBACK_BYTES {\n        bail!(\"FSKit callback response exceeds the bounded frame size\");\n    }\n    let mut bytes = vec![0_u8; length];\n    stream.read_exact(&mut bytes).await?;\n    let response: StorageFilesystemResponseV2 =\n        serde_json::from_slice(&bytes).context(\"decode FSKit callback probe\")?;\n    if response.protocol_version != STORAGE_FILESYSTEM_PROTOCOL_V2 {\n        bail!(\"FSKit callback probe protocol mismatch\");\n    }\n    Ok(response)\n}\n\nasync fn service_loop(\n    listener: &LocalListener,\n    launch: &StorageProviderServiceLaunchV1,\n    mounted: &mut bool,\n) -> Result<()> {\n    let mut poll = tokio::time::interval(SERVICE_POLL);\n    loop {","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-fskit/src/service.rs#L229-L265","documentation":"read_callback_response first reads a 4-byte big-endian length and rejects frames whose length is 0 or greater than MAX_CALLBACK_BYTES. This bound prevents allocating unbounded memory from a hostile or corrupt peer on the local callback socket. A response outside the bound aborts the probe.","triggerScenarios":"read_callback_response (called by probe_callback) reads a length prefix that is 0 (empty frame) or exceeds MAX_CALLBACK_BYTES — e.g. the peer wrote garbage, desynchronized the framing, or sent an oversized JSON blob.","commonSituations":"A stream desync after a previous short read; an extension writing the length in little-endian or as text instead of 4-byte BE; a malicious/stale process connected to the socket.","solutions":["Verify the responder writes a 4-byte big-endian u32 length before the JSON payload","Ensure each response is written on a fresh/synchronized stream so framing stays aligned","Check the payload size against MAX_CALLBACK_BYTES and shrink large responses","Confirm no stale process is bound to the control socket; restart the service"],"exampleFix":"// before: little-endian length on responder side\ntry length.withUnsafeBytes { Data($0) } // LE\n// after\nvar be = length.bigEndian\ntry be.withUnsafeBytes { stream.write(Data($0)) }","handlingStrategy":"validation","validationCode":"fn frame_len_ok(len: usize, max: usize) -> bool { len > 0 && len <= max }","typeGuard":null,"tryCatchPattern":"match read_callback_response(&mut stream).await { Err(e) if e.to_string().contains(\"bounded frame size\") => { mark_stream_desynced(); restart_responder(); } other => other }","preventionTips":["Always write 4-byte big-endian length prefixes","Never reuse a desynchronized stream — reset on any framing error","Keep responses under MAX_CALLBACK_BYTES","Reject non-service processes connecting to the socket"],"tags":["ipc","framing","bounds-check"],"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"}