{"record":{"id":"ed2f90255e0b6630","repo":"BoundaryML/baml","slug":"baml-engine-is-shutting-down","errorCode":null,"errorMessage":"BAML engine is shutting down","messagePattern":"BAML engine is shutting down","errorType":"exception","errorClass":"EngineError","httpStatus":null,"severity":"error","filePath":"baml_language/crates/bex_engine/src/lib.rs","lineNumber":798,"sourceCode":"        // doesn't double-panic.\n        let mut map = self\n            .engine\n            .active_calls\n            .lock()\n            .unwrap_or_else(std::sync::PoisonError::into_inner);\n        map.remove(&self.call_id);\n        let no_active_calls = map.values().all(|call| call.pending);\n        drop(map);\n        if no_active_calls {\n            self.engine.lifecycle_changed.notify_waiters();\n        }\n    }\n}\n\n/// Errors that can occur during engine execution.\n#[derive(Debug, PartialEq, Error, Clone)]\npub enum EngineError {\n    #[error(\"BAML engine is shutting down\")]\n    ShuttingDown,\n\n    #[error(\"Function call with ID {call_id} not found\")]\n    FunctionCallNotFound { call_id: CallId },\n\n    #[error(\"Future with ID {future_id} not found\")]\n    FutureNotFound { future_id: FutureId },\n\n    #[error(\"Function not found: {name}\")]\n    FunctionNotFound { name: String },\n\n    /// Function exists, but its `FunctionKind` is not invokable as an\n    /// engine entry point. Only bytecode functions can be called via\n    /// [`BexEngine::call_function`] / [`BexEngine::call_function_bound_args`]:\n    /// native (`$rust_function`) entries would re-enter the VM through\n    /// `YieldToCall` with no bytecode frame to return to. Sysops + builtins\n    /// reach their natives from inside a calling bytecode body.\n    #[error(\"Function `{name}` is not invokable as an entry point (kind: {kind})\")]","sourceCodeStart":780,"sourceCodeEnd":816,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/bex_engine/src/lib.rs#L780-L816","documentation":"`EngineError::ShuttingDown` is returned when an operation is attempted on the BAML (bex) engine while it is shutting down. Once shutdown begins, the engine stops accepting new calls, futures, or lookups and reports this error to in-flight and new requests. It is a graceful-refusal signal, not a bug.","triggerScenarios":"Calling into `BexEngine` (e.g. `call_function`, submitting work, or awaiting a future) after shutdown has been initiated; racing an engine stop with pending submissions.","commonSituations":"Application shutdown while background tasks still submit engine calls; a test harness dropping the engine while async tasks run; a client holding a stale engine handle after restart.","solutions":["Treat it as terminal: stop submitting work and unwind the caller gracefully.","Await engine shutdown completion before spawning new calls.","If the engine should still be alive, audit handle lifetime and reinitialize the engine before retrying."],"exampleFix":"// before\nlet out = engine.call_function(\"f\", args).await?;\n// after\nif !engine.is_running() { return; }\nlet out = match engine.call_function(\"f\", args).await {\n    Err(EngineError::ShuttingDown) => return Ok(()),\n    other => other?,\n};","handlingStrategy":"try-catch","validationCode":"// rust\nif !engine.is_running() { /* skip submission */ }","typeGuard":null,"tryCatchPattern":"// rust\nmatch engine.call_function(name, args).await {\n    Err(EngineError::ShuttingDown) => /* graceful exit */,\n    other => other?,\n}","preventionTips":["Coordinate engine shutdown with task lifecycles (join before drop)","Use a readiness flag/cancellation token checked before submissions","Avoid long-lived engine handles that outlive intentional shutdown"],"tags":["engine","shutdown","lifecycle","async","rust"],"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-14T05:17:10.506Z"}