Hmbown/CodeWhale · error · anyhow::Error
serialized lane exit receipt exceeds size bound
Error message
serialized lane exit receipt exceeds size bound
What it means
write_lane_exit_receipt serializes LaneExitReceipt {lane_id, exit_code} and refuses to persist it if the JSON exceeds MAX_EXIT_RECEIPT_BYTES (4 KiB, runtime.rs:173). The bound keeps the receipt file a fixed-size, cheap-to-validate artifact that read_lane_exit_receipt can trust. Since the payload is just an id and an integer, exceeding 4 KiB in practice means an absurdly long lane_id or external tampering.
Source
Thrown at crates/lane/src/runtime.rs:378
bail!("invalid lane environment key {key:?}");
}
}
Ok(environment)
}
fn write_lane_exit_receipt(
receipt_path: &Path,
receipt_tmp_path: &Path,
lane_id: &str,
exit_code: i32,
) -> Result<()> {
let encoded = serde_json::to_vec(&LaneExitReceipt {
lane_id: lane_id.to_string(),
exit_code,
})
.context("serialize lane exit receipt")?;
if encoded.len() as u64 > MAX_EXIT_RECEIPT_BYTES {
bail!("serialized lane exit receipt exceeds size bound");
}
remove_file_if_present(receipt_tmp_path)?;
let mut options = OpenOptions::new();
options.create_new(true).write(true);
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt;
options.mode(0o600);
}
let result = (|| {
let mut file = options
.open(receipt_tmp_path)
.with_context(|| format!("create {}", receipt_tmp_path.display()))?;
file.write_all(&encoded)
.with_context(|| format!("write {}", receipt_tmp_path.display()))?;
file.sync_all()
.with_context(|| format!("sync {}", receipt_tmp_path.display()))?;
fs::rename(receipt_tmp_path, receipt_path)View on GitHub (pinned to 0c42157ee5)
Solutions
- Shorten the lane id (a UUID or short slug is plenty) and retry
- Cap lane id length where ids are generated, before they reach the runtime
- If the id looks normal, check for tampering or corruption in the values feeding the receipt
Example fix
// before
let lane_id = format!("{}-{}", uuid, user_supplied_description); // unbounded
// after
let lane_id = format!("lane-{}", uuid.simple());
assert!(lane_id.len() <= 128); Defensive patterns
Strategy: validation
Validate before calling
fn lane_id_within_receipt_bound(lane_id: &str) -> bool {
// Receipt = {"lane_id":"...","exit_code":N}; 4 KiB bound in runtime.rs:173.
lane_id.len() + 64 <= 4 * 1024
} Prevention
- Cap lane id length at generation time (128 chars is generous)
- Never build lane ids from unbounded user input
When it happens
Trigger: Calling a lane start/stop flow that reaches write_lane_exit_receipt with a lane_id whose UTF-8 JSON encoding plus wrapper exceeds 4096 bytes (thousands of characters).
Common situations: Generating lane ids from raw UUIDs concatenated with paths, full descriptions, or user input; fuzzing or adversarial input feeding the lane id; a misconfigured id generator producing megabyte-long strings.
Related errors
- lane exit receipt {} exceeds {} bytes
- lane exit receipt {} belongs to {}, expected {}
- project workspace path cannot be empty
- terminal lane transition requires a terminal status
- unknown runtime backend `{other}` (use tmux|inline|vm|ci)
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/3c007f350d076273.
Report an issue: GitHub.