block/buzz · error · std::io::Error

io: line exceeds max ({max} bytes)

Error message

io: line exceeds max ({max} bytes)

What it means

buzz-agent speaks newline-delimited JSON over stdio. wire::read_bounded_line accumulates chunks from BufReader<Stdin> until a '\n'; before extending, it checks the accumulated size against the caller-supplied cap and returns InvalidData 'io: line exceeds max' when a single frame would exceed it. The cap is cfg.max_line_bytes (BUZZ_AGENT_MAX_LINE_BYTES, default 4 MiB, with a MIN_LINE_BYTES floor — see config.rs:461,616,708). The error is fatal to the reader loop in lib.rs:214, so the agent process terminates the session.

Source

Thrown at crates/buzz-agent/src/wire.rs:408

) -> std::io::Result<Option<String>> {
    let mut buf: Vec<u8> = Vec::new();
    loop {
        let chunk = stdin.fill_buf().await?;
        if chunk.is_empty() {
            if !buf.is_empty() {
                tracing::error!(
                    "io: unterminated frame at EOF ({} bytes dropped)",
                    buf.len()
                );
            }
            return Ok(None);
        }
        let take = chunk
            .iter()
            .position(|b| *b == b'\n')
            .map_or(chunk.len(), |i| i + 1);
        if buf.len().saturating_add(take) > max {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidData,
                format!("io: line exceeds max ({max} bytes)"),
            ));
        }
        buf.extend_from_slice(&chunk[..take]);
        stdin.consume(take);
        if buf.ends_with(b"\n") {
            buf.pop();
            if buf.ends_with(b"\r") {
                buf.pop();
            }
            match String::from_utf8(buf) {
                Ok(s) => return Ok(Some(s)),
                Err(_) => {
                    return Err(std::io::Error::new(
                        std::io::ErrorKind::InvalidData,
                        "io: frame contains invalid UTF-8",
                    ))

View on GitHub (pinned to eed74bde2f)

Solutions

  1. Raise the cap: `export BUZZ_AGENT_MAX_LINE_BYTES=16777216` (16 MiB) and restart the agent — must stay above MIN_LINE_BYTES.
  2. Shrink the payload: send images/files by reference or chunk tool results instead of inlining multi-MB base64 in one frame.
  3. Verify the sender terminates every JSON frame with '\n' — an unterminated stream grows the buffer until it trips the cap.
  4. Check for accidentally duplicated payloads (history echoed twice) inflating frame size.

Example fix

# before: default 4 MiB cap, agent dies on a 6 MB base64 frame
# io: line exceeds max (4194304 bytes)

# after
export BUZZ_AGENT_MAX_LINE_BYTES=16777216
Defensive patterns

Strategy: validation

Validate before calling

// sender-side guard before writing a frame to the agent's stdin
fn frame_fits(line: &str, max: usize) -> bool {
    line.len() + 1 <= max // +1 for the trailing newline
}
assert!(frame_fits(&json_line, cfg.max_line_bytes));

Type guard

fn is_within_line_budget(line: &str, max_line_bytes: usize) -> bool {
    line.len() < max_line_bytes
}

Try / catch

// on the reader side, treat an over-limit line as a protocol error for THIS frame
// rather than killing the loop if you control the harness:
match wire::read_bounded_line(&mut stdin, max_line).await {
    Ok(Some(line)) => handle(line),
    Ok(None) => break,
    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => { /* log frame size, skip session */ break }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: read_bounded_line(&mut stdin, max_line) errors when one stdin line exceeds max bytes before its '\n': a session/new or turn request embedding a multi-megabyte base64 image, a huge tool result or history echoed back in one JSON frame, or a client that streams a single JSON object without a newline for more than BUZZ_AGENT_MAX_LINE_BYTES bytes.

Common situations: ACP harness piping screenshot attachments inline as base64 (each image inflates ~4/3x); default 4 MiB cap met by long agentic sessions with accumulated history; someone lowers BUZZ_AGENT_MAX_LINE_BYTES for testing and forgets; a misbehaving writer never sends '\n' so the whole stream is treated as one line.

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 block/buzz@eed74bde2f (2026-08-20). Data as JSON: /api/errors/0bee1f77d15cf495. Report an issue: GitHub.