Hmbown/CodeWhale · error · anyhow::Error
lane exit receipt {} exceeds {} bytes
Error message
lane exit receipt {} exceeds {} bytes What it means
read_lane_exit_receipt stats the receipt file and refuses to read it if it is larger than MAX_EXIT_RECEIPT_BYTES (4 KiB). The log proxy writes receipts far below this bound, so an oversized file signals corruption, truncation-garbage, or a foreign file sitting at lane_exit_receipt_path(log_path). The guard protects the reconciler from loading arbitrary data.
Source
Thrown at crates/lane/src/runtime.rs:524
.map_err(|_| anyhow::anyhow!("lane proxy stderr logger panicked"))?;
let mut exit_code = exit_status_code(status);
if let Some(error) = stdout_result.err().or_else(|| stderr_result.err()) {
append_proxy_failure(&log_path, &lane_id, &error)?;
exit_code = LANE_PROXY_FAILURE_EXIT_CODE;
}
write_lane_exit_receipt(&receipt_path, &receipt_tmp_path, &lane_id, exit_code)?;
Ok(exit_code)
}
fn read_lane_exit_receipt(log_path: &Path, lane_id: &str) -> Result<Option<LaneExitReceipt>> {
let path = lane_exit_receipt_path(log_path);
let metadata = match std::fs::metadata(&path) {
Ok(metadata) => metadata,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None),
Err(err) => return Err(err).with_context(|| format!("stat {}", path.display())),
};
if metadata.len() > MAX_EXIT_RECEIPT_BYTES {
bail!(
"lane exit receipt {} exceeds {} bytes",
path.display(),
MAX_EXIT_RECEIPT_BYTES
);
}
let bytes = std::fs::read(&path).with_context(|| format!("read {}", path.display()))?;
let receipt: LaneExitReceipt =
serde_json::from_slice(&bytes).with_context(|| format!("parse {}", path.display()))?;
if receipt.lane_id != lane_id {
bail!(
"lane exit receipt {} belongs to {}, expected {}",
path.display(),
receipt.lane_id,
lane_id
);
}
Ok(Some(receipt))
}View on GitHub (pinned to 0c42157ee5)
Solutions
- Inspect the file named in the message and delete it — a missing receipt is tolerated (read returns Ok(None)) and reconciliation falls back to tmux session state
- Verify the log proxy binary is the runtime's own, not a wrapper adding output
- Use a fresh log directory per lane generation to avoid inheriting foreign files
Defensive patterns
Strategy: fallback
Validate before calling
fn receipt_readable(path: &std::path::Path) -> bool {
std::fs::metadata(path)
.map(|m| m.len() <= 4 * 1024)
.unwrap_or(false)
} Try / catch
match read_lane_exit_receipt(&log_path, &lane_id) {
Ok(receipt) => { /* use exit code */ }
Err(err) if err.to_string().contains("exceeds") => {
// Oversized/corrupt receipt: remove it and reconcile via tmux state instead.
let _ = std::fs::remove_file(lane_exit_receipt_path(&log_path));
}
Err(err) => return Err(err),
} Prevention
- Keep the lane log directory exclusive to the runtime and its log proxy
- Do not wrap or replace the log proxy with tooling that appends extra output to the receipt path
- Size-check the receipt during reconciliation cleanup routines
When it happens
Trigger: Reconciling a lane (e.g. after a crash) where the receipt path under the lane's log directory holds a file > 4096 bytes — concatenated/truncated writes, a different tool's output, or a receipt from an incompatible format.
Common situations: A crashed writer leaving a partially-written receipt that was appended to across runs; log directories reused or shared between tools; disk corruption; the log proxy being replaced by a script that writes extra content to the same path.
Related errors
- serialized lane exit receipt exceeds size bound
- private lane environment {} exceeds {} bytes
- lane exit receipt {} belongs to {}, expected {}
- project workspace path cannot be empty
- project workspace path cannot contain '..' components
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/206ac4afc8decbeb.
Report an issue: GitHub.