{"record":{"id":"4c5b94ce887890f6","repo":"BoundaryML/baml","slug":"history-boundary-was-not-begun","errorCode":null,"errorMessage":"history boundary {} was not begun","messagePattern":"history boundary (.+?) was not begun","errorType":"error_code","errorClass":"io::Error","httpStatus":404,"severity":"error","filePath":"baml_language/crates/bex_events/src/history/mod.rs","lineNumber":180,"sourceCode":"                writer,\n            },\n        );\n        Ok(())\n    }\n\n    pub fn append_log_body(\n        &self,\n        boundary_id: BoundaryId,\n        event: LogEventRecord,\n        codec: ValueCodec,\n        body: Vec<u8>,\n    ) -> io::Result<ValueWriteOutcome> {\n        let mut inner = self\n            .inner\n            .lock()\n            .unwrap_or_else(std::sync::PoisonError::into_inner);\n        let state = inner.boundaries.get_mut(&boundary_id).ok_or_else(|| {\n            io::Error::new(\n                io::ErrorKind::NotFound,\n                format!(\n                    \"history boundary {} was not begun\",\n                    boundary_id.to_wire_string()\n                ),\n            )\n        })?;\n        state.writer.append_log_body(event, codec, body)\n    }\n\n    pub fn append_capture_loss(\n        &self,\n        boundary_id: BoundaryId,\n        record: &CaptureLossRecord,\n    ) -> io::Result<()> {\n        let mut inner = self\n            .inner\n            .lock()","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/bex_events/src/history/mod.rs#L162-L198","documentation":"append_log_body requires that a history boundary was previously begun with the given BoundaryId. The boundaries map holds per-boundary state; if the ID is absent, an io::Error of kind NotFound is produced saying the boundary was not begun. It surfaces as a NotFound error from append_log_body.","triggerScenarios":"Calling append_log_body(boundary_id, ...) with a BoundaryId that was never created via begin_boundary, or one that came from a different History instance/thread.","commonSituations":"Race between threads where logs are appended before the boundary-start call completes; reusing a stale boundary ID after a History was recreated; ordering bugs in test harnesses (e.g. replay_orders_logs_chronologically_across_threads) that append before begin.","solutions":["Call begin_boundary (or the boundary-opening API) before append_log_body and reuse the returned BoundaryId.","Ensure the same History instance that began the boundary is used for appends.","Synchronize threads so begin completes before any append on that boundary.","Check the ID's wire string in the message against registered boundaries to spot ID mix-ups."],"exampleFix":"// before\nhistory.append_log_body(boundary_id, record)?;\n// after\nlet boundary_id = history.begin_boundary(&run_started)?;\nhistory.append_log_body(boundary_id, record)?;","handlingStrategy":"validation","validationCode":"if !begun_boundaries.contains(&boundary_id) {\n    return Err(\"append_log_body called before begin_boundary\".into());\n}","typeGuard":null,"tryCatchPattern":"match history.append_log_body(boundary_id, record) {\n    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {\n        let id = history.begin_boundary(&run_started)?;\n        history.append_log_body(id, record)?\n    }\n    other => other?,\n}","preventionTips":["Always call begin_boundary before any append and thread the returned ID.","Keep boundary IDs with the owning History instance; never share IDs across instances.","In multi-threaded writers, begin the boundary before spawning appenders."],"tags":["io","not-found","state","history"],"backgroundTag":"invalid-state-transition","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}