astrid-runtime/astrid · error

WinFsp service control request exceeds limit

Error message

WinFsp service control request exceeds limit

What it means

read_service_control reads one newline-delimited JSON control request from the local stream, capped at SERVICE_MAX_CONTROL_BYTES (64 KiB). If the line is empty (EOF) or longer than 64 KiB, the request is rejected to bound memory use and prevent abuse of the control socket.

Solutions

  1. Split large control payloads into smaller requests or use the file-based control channel instead of the socket line protocol.
  2. Ensure the control client appends a newline and keeps each JSON request under 64 KiB.
  3. Fix health-check/probe clients to send a minimal valid request or close cleanly without partial writes.
  4. Check the client for binary/UTF-8-invalid output that prevents the line terminator from appearing.

Example fix

// before
let giant = serde_json::to_string(&huge_request)?; // > 64 KiB
stream.write_all(giant.as_bytes()).await?;
// after
let compact = serde_json::to_string(&request.trim_to_control_limit())?;
stream.write_all(format!("{compact}\n").as_bytes()).await?;
Defensive patterns

Strategy: validation

Validate before calling

const SERVICE_MAX_CONTROL_BYTES: usize = 64 * 1024;
fn control_request_is_within_limit(json: &str) -> bool {
    !json.is_empty() && json.len() <= SERVICE_MAX_CONTROL_BYTES && json.ends_with('\n')
}

Try / catch

match send_control(&stream, &request).await {
    Err(e) if e.to_string().contains("exceeds limit") => {
        // shrink or split the control request below 64 KiB and retry
        Err(e)
    },
    other => other,
}

Prevention

When it happens

Trigger: A control client connects to the control socket and sends a line longer than 65535 bytes, or closes the connection before sending any data (read == 0).

Common situations: A custom tool writing oversized JSON control commands; a client that dumps a blob without newlines so the whole payload exceeds the cap; connecting and disconnecting without writing (health-check probes); binary data sent to the socket with no newline.

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/893288fbc7901038. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-storage-provider-winfsp/src/win.rs:434

                    return Ok(());
                }
            },
        }
    }
}

async fn read_service_control(
    stream: &mut local_transport::LocalStream,
) -> Result<ServiceControlRequest> {
    let mut line = String::new();
    let reader = tokio::io::BufReader::new(stream);
    let read = reader
        .take((SERVICE_MAX_CONTROL_BYTES + 1) as u64)
        .read_line(&mut line)
        .await
        .context("read WinFsp service control request")?;
    if read == 0 || line.len() > SERVICE_MAX_CONTROL_BYTES {
        bail!("WinFsp service control request exceeds limit");
    }
    serde_json::from_str(&line).context("decode WinFsp service control request")
}

async fn write_service_control(
    stream: &mut local_transport::LocalStream,
    response: &ServiceControlResponse,
) -> Result<()> {
    let bytes = serde_json::to_vec(response)?;
    stream.write_all(&bytes).await?;
    stream.write_all(b"\n").await?;
    stream.flush().await.context("flush WinFsp service control")
}

fn parent_is_alive(
    parent: &astrid_core::storage_filesystem::StorageProviderParentLifetimeV1,
) -> bool {
    // SAFETY: OpenProcess/GetExitCodeProcess/CloseHandle are called with a

View on GitHub (pinned to affd8760f4)