{"record":{"id":"d907f741102b2b50","repo":"BoundaryML/baml","slug":"a-function-call-with-id-call-id-is-already-in-progress","errorCode":null,"errorMessage":"A function call with ID {call_id} is already in progress","messagePattern":"A function call with ID (.+?) is already in progress","errorType":"exception","errorClass":"EngineError","httpStatus":null,"severity":"error","filePath":"baml_language/crates/bex_engine/src/lib.rs","lineNumber":855,"sourceCode":"    /// BAML `int` is `i64`, so the signal carries the full value; the\n    /// caller clamps into its shell's range (typically 0..=255 on Unix).\n    #[error(\"baml.sys.exit({code})\")]\n    Exit { code: i64 },\n\n    #[error(\"Cannot convert object of type {type_name}\")]\n    CannotConvert { type_name: String },\n\n    #[error(\"Type mismatch: {message}\")]\n    TypeMismatch { message: String },\n\n    #[error(\"Schema inconsistency: {message}\")]\n    SchemaInconsistency { message: String },\n\n    #[cfg(feature = \"heap_debug\")]\n    #[error(\"Snapshot not possible for type: {type_name}\")]\n    CannotSnapshot { type_name: String },\n\n    #[error(\"A function call with ID {call_id} is already in progress\")]\n    DuplicateCallId { call_id: CallId },\n\n    #[error(\"Package initialization failed: {0}\")]\n    InitFailed(String),\n\n    #[error(\"{0}\")]\n    Other(String),\n}\n\nfn format_vm_internal_error(\n    err: &bex_vm::errors::VmInternalError,\n    trace: &[bex_vm::StackFrame],\n) -> String {\n    use std::fmt::Write;\n    let mut out = bex_vm::format_traceback(\n        trace\n            .iter()\n            .map(|f| (f.file_path.as_str(), f.error_line, f.function_name.as_str())),","sourceCodeStart":837,"sourceCodeEnd":873,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/bex_engine/src/lib.rs#L837-L873","documentation":"A call was registered with a CallId that the engine already has an in-progress call for. CallIds are expected to be unique per concurrent invocation; a duplicate means the caller is reusing an ID while the original call has not completed.","triggerScenarios":"Host code starting a BAML function call with an ID it already used for a still-active call (e.g. retrying without generating a fresh ID, or reentrant invocation with a cached ID).","commonSituations":"Client code implementing its own call tracking/retries; resuming streams after errors without rotating the call ID; concurrent requests generated from the same ID seed.","solutions":["Generate a fresh unique CallId for each invocation (e.g. UUID)","Wait for the original call with that ID to finish before reusing it","On retry-after-failure, allocate a new ID instead of reusing the failed one","Track and clear call IDs in a registry when calls complete"],"exampleFix":"// before\ncall_engine(call_id) // reused id\n// after\nlet call_id = Uuid::new_v4().to_string();\ncall_engine(call_id)","handlingStrategy":"validation","validationCode":"let mut active: HashSet<CallId> = HashSet::new();\nlet call_id = Uuid::new_v4().to_string();\nassert!(active.insert(call_id.clone()), \"call id already in progress\");","typeGuard":null,"tryCatchPattern":"match result {\n    Err(EngineError::DuplicateCallId { call_id }) => {\n        let fresh = Uuid::new_v4().to_string();\n        retry_with_id(fresh)?;\n    }\n    Ok(v) => use(v),\n    Err(e) => handle(e),\n}","preventionTips":["Generate a unique ID (UUID) per invocation","Remove IDs from your tracking set when calls complete","Never reuse an ID across retries without checking completion"],"tags":["concurrency","call-id","duplicate"],"backgroundTag":"invalid-argument-value","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"}