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

  1. Shorten the lane id (a UUID or short slug is plenty) and retry
  2. Cap lane id length where ids are generated, before they reach the runtime
  3. 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

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


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/3c007f350d076273. Report an issue: GitHub.