astrid-runtime/astrid · error
FSKit callback response exceeds the bounded frame size
Error message
FSKit callback response exceeds the bounded frame size
What it means
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.
Source
Thrown at crates/astrid-storage-provider-fskit/src/service.rs:247
stream.flush().await?;
let response = read_callback_response(&mut stream).await?;
if response.request_id != request.request_id {
bail!("FSKit callback probe correlation mismatch");
}
match response.outcome {
StorageFilesystemOutcomeV2::Success(_) => Ok(()),
StorageFilesystemOutcomeV2::Failure(StorageFilesystemFailureV1 { code, message }) => {
bail!("FSKit callback probe failed [{code}]: {message}")
},
}
}
async fn read_callback_response(stream: &mut LocalStream) -> Result<StorageFilesystemResponseV2> {
let mut length = [0_u8; 4];
stream.read_exact(&mut length).await?;
let length = u32::from_be_bytes(length) as usize;
if length == 0 || length > MAX_CALLBACK_BYTES {
bail!("FSKit callback response exceeds the bounded frame size");
}
let mut bytes = vec![0_u8; length];
stream.read_exact(&mut bytes).await?;
let response: StorageFilesystemResponseV2 =
serde_json::from_slice(&bytes).context("decode FSKit callback probe")?;
if response.protocol_version != STORAGE_FILESYSTEM_PROTOCOL_V2 {
bail!("FSKit callback probe protocol mismatch");
}
Ok(response)
}
async fn service_loop(
listener: &LocalListener,
launch: &StorageProviderServiceLaunchV1,
mounted: &mut bool,
) -> Result<()> {
let mut poll = tokio::time::interval(SERVICE_POLL);
loop {View on GitHub (pinned to affd8760f4)
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
Example fix
// before: little-endian length on responder side
try length.withUnsafeBytes { Data($0) } // LE
// after
var be = length.bigEndian
try be.withUnsafeBytes { stream.write(Data($0)) } Defensive patterns
Strategy: validation
Validate before calling
fn frame_len_ok(len: usize, max: usize) -> bool { len > 0 && len <= max } Try / catch
match read_callback_response(&mut stream).await { Err(e) if e.to_string().contains("bounded frame size") => { mark_stream_desynced(); restart_responder(); } other => other } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
- FSKit service control request exceeds limit
- FUSE callback response exceeds the bounded frame size
- IPC frame too large: {len} bytes
- IPC frame overflow
- opaque capsule assets cannot be symlinks: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/a82e778c738f467c.
Report an issue: GitHub.