astrid-runtime/astrid · error

FSKit service control request exceeds limit

Error message

FSKit service control request exceeds limit

What it means

read_control reads one newline-delimited JSON control request from the service socket using a take(MAX_CONTROL_BYTES + 1) cap. If the line is empty (EOF) or longer than MAX_CONTROL_BYTES, it is rejected. This bounds memory per control message and treats EOF-with-no-data as a protocol error.

Source

Thrown at crates/astrid-storage-provider-fskit/src/service.rs:317

            _ = poll.tick() => {
                if !parent_is_alive(&launch.parent) || probe_callback(launch).await.is_err() {
                    return Ok(());
                }
            },
        }
    }
}

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

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

#[cfg(unix)]
fn parent_is_alive(
    parent: &astrid_core::storage_filesystem::StorageProviderParentLifetimeV1,
) -> bool {
    use nix::sys::signal::kill;
    use nix::unistd::Pid;

View on GitHub (pinned to affd8760f4)

Solutions

  1. Ensure control clients send newline-terminated JSON within MAX_CONTROL_BYTES
  2. Split oversized control requests or extend MAX_CONTROL_BYTES deliberately if legitimate payloads grew
  3. Verify no stray process is writing to the control socket path
  4. Check the client didn't crash mid-write (EOF case) and reconnect

Example fix

// client side
// before
stream.write_all(payload)?;
// after
stream.write_all(payload)?;
stream.write_all(b"\n")?;
Defensive patterns

Strategy: validation

Validate before calling

fn control_payload_ok(json: &str, max: usize) -> bool { json.len() <= max && json.ends_with('\n') }

Try / catch

match read_control(&mut reader).await { Err(e) if e.to_string().contains("exceeds limit") => { drop_client(); continue; } other => other }

Prevention

When it happens

Trigger: read_control receives either 0 bytes before newline (client disconnected without sending) or a line exceeding MAX_CONTROL_BYTES — e.g. a client sending a huge un-terminated line or binary garbage on the control socket.

Common situations: A client writing a control request without a trailing newline then being truncated; an over-large serialized request; something other than the intended client connected to the socket and wrote junk.

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/5129e941261c9164. Report an issue: GitHub.