astrid-runtime/astrid · error

FUSE service control response exceeds the bounded frame size

Error message

FUSE service control response exceeds the bounded frame size

What it means

This error means the response line read from the FUSE service control socket was longer than the 64 KiB `MAX_CONTROL_FRAME_BYTES` bound. The reader uses `take(MAX + 1)` so oversized responses are detected rather than read unboundedly, and the library refuses to decode a frame that violates the protocol. It is thrown from `read_control_response` in crates/astrid-storage-provider-fuse/src/control.rs:167 before `serde_json::from_str` is attempted.

Source

Thrown at crates/astrid-storage-provider-fuse/src/control.rs:167

    let bytes = serde_json::to_vec(request)?;
    if bytes.len() >= MAX_CONTROL_FRAME_BYTES {
        bail!("FUSE control request exceeds the bounded frame size");
    }
    stream.write_all(&bytes)?;
    stream.write_all(b"\n")?;
    stream.flush()?;
    let mut reader = BufReader::new(stream);
    read_control_response(&mut reader)
}

fn read_control_response(reader: &mut BufReader<UnixStream>) -> Result<ControlResponse> {
    let mut line = String::new();
    let mut limited = reader.take((MAX_CONTROL_FRAME_BYTES + 1) as u64);
    limited
        .read_line(&mut line)
        .context("read FUSE service control response")?;
    if line.len() > MAX_CONTROL_FRAME_BYTES {
        bail!("FUSE service control response exceeds the bounded frame size");
    }
    serde_json::from_str(&line).context("decode FUSE service control response")
}

/// Remove the control endpoint and auto-created empty mountpoint.
pub(crate) fn cleanup_service_artifacts(
    control_path: &Path,
    mountpoint: &Path,
    auto_created: bool,
) -> Result<()> {
    let _ = std::fs::remove_file(control_path);
    if auto_created
        && !mountinfo_contains(mountpoint)?
        && std::fs::symlink_metadata(mountpoint).is_ok_and(|metadata| metadata.is_dir())
        && std::fs::read_dir(mountpoint)?.next().is_none()
    {
        let _ = std::fs::remove_dir(mountpoint);
    }

View on GitHub (pinned to affd8760f4)

Solutions

  1. Inspect what the FUSE service is writing to the control socket; fix oversized response payloads at the service side.
  2. Ensure client and service use the same crate version so MAX_CONTROL_FRAME_BYTES and response shape agree.
  3. Check that the service terminates every response with a newline (the frame protocol requires it).
  4. If responses legitimately need more room, raise the bound on both sides deliberately.

Example fix

// service-side: keep responses small
// before
ControlResponse::Failure { code, message: format!("{huge_debug_dump}") }
// after
ControlResponse::Failure { code, message: truncate(&huge_debug_dump, 1024) }
Defensive patterns

Strategy: try-catch

Type guard

fn is_oversize(line: &str) -> bool { line.len() > 64 * 1024 }

Try / catch

match call_control(&sock, &req) {
    Err(e) if e.to_string().contains("exceeds the bounded frame size") => {
        // restart service / shrink response, then retry
    }
    r => r?,
}

Prevention

When it happens

Trigger: The detached FUSE service wrote a control response whose single newline-delimited line exceeds 65536 bytes; the read is invoked via `call_control`.

Common situations: A buggy or mismatched-version service serializing a huge failure payload (e.g. embedding a full stack trace or dump); a peer that never terminates lines, causing the take() limit to fill without a newline; hostile/broken socket peer sending garbage.

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


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/ee475b91685c70ca. Report an issue: GitHub.