xai-org/grok-build · error · io::Error (InvalidData)
ACP message exceeds {} byte limit ({} bytes read)
Error message
ACP message exceeds {} byte limit ({} bytes read) What it means
Thrown by `read_line_capped` in the ACP (Agent Client Protocol) line reader when a single newline-delimited message exceeds MAX_LINE_SIZE bytes. Because ACP frames are length-unbounded JSON lines, this guard prevents unbounded memory growth from a malicious or buggy peer. The reader consumes the bytes, sees buf.len() > MAX_LINE_SIZE, and returns InvalidData before any parsing occurs.
Source
Thrown at crates/codegen/xai-acp-lib/src/line_reader.rs:164
let (consumed, done) = {
let available = reader.fill_buf().await?;
if available.is_empty() {
return Ok(buf.len()); // EOF
}
match available.iter().position(|&b| b == b'\n') {
Some(pos) => {
buf.extend_from_slice(&available[..=pos]);
(pos + 1, true)
}
None => {
buf.extend_from_slice(available);
(available.len(), false)
}
}
};
reader.consume_unpin(consumed);
if buf.len() > MAX_LINE_SIZE {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"ACP message exceeds {} byte limit ({} bytes read)",
MAX_LINE_SIZE,
buf.len()
),
));
}
if done {
return Ok(buf.len());
}
}
}
#[cfg(test)]
mod tests {
use futures::{AsyncReadExt as _, io::Cursor};
View on GitHub (pinned to bc7f02eddd)
Solutions
- Truncate or paginate large payloads on the sending side (chunk tool outputs, use file references) so no single ACP line exceeds the limit.
- Verify the peer actually terminates every JSON message with a newline; fix any writer that omits it.
- If legitimately large messages are expected, raise MAX_LINE_SIZE in xai-acp-lib to a safe upper bound.
- Confirm the transport carries text ACP frames, not binary/interleaved output from another process.
Example fix
// before (sender, agent side) let msg = serde_json::to_vec(&huge_result)?; stream.write_all(&msg).await?; // after let msg = serde_json::to_vec(&truncate_result(&huge_result, MAX_INLINE_BYTES))?; stream.write_all(&msg).await?; stream.write_all(b"\n").await?;
Defensive patterns
Strategy: type-guard
Type guard
fn is_oversized_acp_message(err: &io::Error) -> bool {
err.kind() == io::ErrorKind::InvalidData
&& err.to_string().contains("ACP message exceeds")
} Try / catch
match reader.read_line_capped(&mut buf).await {
Ok(n) => parse(&buf[..n])?,
Err(e) if is_oversized_acp_message(&e) => {
tracing::warn!("peer sent oversized ACP line; dropping frame");
// resync reader on next newline
}
Err(e) => return Err(e.into()),
} Prevention
- Truncate or chunk large payloads on the sending agent before writing
- Always terminate JSON messages with a newline on the wire
- Never connect the ACP reader to binary or third-party output streams
- Review MAX_LINE_SIZE when payloads are expected to grow
When it happens
Trigger: Reading from an ACP stream whose peer emits a line longer than MAX_LINE_SIZE — an oversized JSON-RPC notification/result (e.g. a huge tool output inlined in a message), a missing newline causing frames to merge, or a non-ACP peer writing arbitrary data to the pipe.
Common situations: Agent returning enormous file contents or diffs inline in one message; protocol desync where a payload without a trailing newline swallows subsequent frames; connecting the reader to a stream that emits binary data.
Related errors
- response parse error: {e}
- ACP response missing result field
- FS_OTHER
- ACP error: {err}
- No auth methods available
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/86fae5423064a6ff.
Report an issue: GitHub.