BoundaryML/baml · error · io::Error
value record mixed run_started with run_completed lifecycle
Error message
value record mixed run_started with run_completed lifecycle metadata
What it means
When decoding a value file record (file_record_from_proto), a record carrying both run_started and run_completed lifecycle metadata is rejected: one record may describe at most one lifecycle event. This protects the event-file format's invariant that lifecycle bookkeeping is stored in dedicated records, and is surfaced as an io::Error with InvalidData kind from read_bamlvalue_from_bytes.
Source
Thrown at baml_language/crates/bex_events/src/value/read.rs:60
records.push(file_record_from_proto(record)?);
buf = rest;
}
Ok(BamlvalueContents {
header,
records,
truncated,
})
}
fn file_record_from_proto(record: pb::ValueRecordV1) -> io::Result<ValueFileRecord> {
let has_run_started = record.run_started.is_some();
let has_run_completed = record.run_completed.is_some();
let has_lifecycle = has_run_started || has_run_completed;
let has_log_event = record.log_event.is_some();
let has_capture_loss = record.capture_loss.is_some();
if has_run_started && has_run_completed {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"value record mixed run_started with run_completed lifecycle metadata",
));
}
if has_lifecycle
&& (record.metadata.is_some()
|| !record.body.is_empty()
|| has_log_event
|| has_capture_loss
|| record.blob.is_some())
{
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"value record mixed body metadata with lifecycle metadata",
));
}
if let Some(started) = record.run_started {
return Ok(ValueFileRecord::RunStarted(started.try_into()?));View on GitHub (pinned to bd85ce9dee)
Solutions
- Regenerate the value file by re-running the workflow; do not attempt to repair the mixed record by hand.
- If you author .bamlvalue files programmatically, emit run_started and run_completed as separate records.
- Check for concurrent writers — each run must write to its own value file.
Example fix
// before record.run_started = Some(started); record.run_completed = Some(completed); // same record // after write_record(ValueFileRecord::RunStarted(started)); write_record(ValueFileRecord::RunCompleted(completed));
Defensive patterns
Strategy: try-catch
Try / catch
match read_bamlvalue_from_bytes(&bytes) {
Ok(v) => v,
Err(e) if e.to_string().contains("lifecycle") => {
eprintln!("value file corrupted (mixed lifecycle record): {e}");
// fall back to re-running the workflow / restoring a backup
}
Err(e) => return Err(e.into()),
} Prevention
- Write run_started and run_completed as separate records, one per record.
- Never append to a value file from multiple processes concurrently.
- Avoid post-processing or rewriting .bamlvalue files with external tools.
When it happens
Trigger: read_bamlvalue_from_bytes() on a value file whose protobuf record has both the run_started and run_completed oneofs set — typically a corrupted, hand-edited, or incorrectly merged file.
Common situations: Files corrupted by concurrent writers appending to the same value file, buggy external tooling that rewrites records, or merging/truncation mishaps that splice records together.
Related errors
- value record mixed body metadata with lifecycle metadata
- value record mixed capture loss metadata with body metadata
- value record omitted metadata
- body record omitted log metadata
- value metadata omitted codec
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/a93803c0132ac959.
Report an issue: GitHub.