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
- Raise the cap: `export BUZZ_AGENT_MAX_LINE_BYTES=16777216` (16 MiB) and restart the agent — must stay above MIN_LINE_BYTES.
- Shrink the payload: send images/files by reference or chunk tool results instead of inlining multi-MB base64 in one frame.
- Verify the sender terminates every JSON frame with '\n' — an unterminated stream grows the buffer until it trips the cap.
- 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
- Size BUZZ_AGENT_MAX_LINE_BYTES to the largest base64 payload you intend to inline (remember ~1.37x inflation).
- Pass large blobs by reference/attachment id instead of embedding them in stdio frames.
- Always terminate frames with '\n' in harnesses; unterminated streams eventually trip this cap.
- Log frame sizes on the producer side in dev to see how close you run to the 4 MiB default.
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
- io: frame contains invalid UTF-8
- failed to sign system message: {e}
- failed to install rustls crypto provider
- connect to test DB
- push HTTP client
AI-assisted analysis of block/buzz@eed74bde2f (2026-08-20).
Data as JSON: /api/errors/0bee1f77d15cf495.
Report an issue: GitHub.