BoundaryML/baml · error · EngineError

A function call with ID {call_id} is already in progress

Error message

A function call with ID {call_id} is already in progress

What it means

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.

Source

Thrown at baml_language/crates/bex_engine/src/lib.rs:855

    /// BAML `int` is `i64`, so the signal carries the full value; the
    /// caller clamps into its shell's range (typically 0..=255 on Unix).
    #[error("baml.sys.exit({code})")]
    Exit { code: i64 },

    #[error("Cannot convert object of type {type_name}")]
    CannotConvert { type_name: String },

    #[error("Type mismatch: {message}")]
    TypeMismatch { message: String },

    #[error("Schema inconsistency: {message}")]
    SchemaInconsistency { message: String },

    #[cfg(feature = "heap_debug")]
    #[error("Snapshot not possible for type: {type_name}")]
    CannotSnapshot { type_name: String },

    #[error("A function call with ID {call_id} is already in progress")]
    DuplicateCallId { call_id: CallId },

    #[error("Package initialization failed: {0}")]
    InitFailed(String),

    #[error("{0}")]
    Other(String),
}

fn format_vm_internal_error(
    err: &bex_vm::errors::VmInternalError,
    trace: &[bex_vm::StackFrame],
) -> String {
    use std::fmt::Write;
    let mut out = bex_vm::format_traceback(
        trace
            .iter()
            .map(|f| (f.file_path.as_str(), f.error_line, f.function_name.as_str())),

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Generate a fresh unique CallId for each invocation (e.g. UUID)
  2. Wait for the original call with that ID to finish before reusing it
  3. On retry-after-failure, allocate a new ID instead of reusing the failed one
  4. Track and clear call IDs in a registry when calls complete

Example fix

// before
call_engine(call_id) // reused id
// after
let call_id = Uuid::new_v4().to_string();
call_engine(call_id)
Defensive patterns

Strategy: validation

Validate before calling

let mut active: HashSet<CallId> = HashSet::new();
let call_id = Uuid::new_v4().to_string();
assert!(active.insert(call_id.clone()), "call id already in progress");

Try / catch

match result {
    Err(EngineError::DuplicateCallId { call_id }) => {
        let fresh = Uuid::new_v4().to_string();
        retry_with_id(fresh)?;
    }
    Ok(v) => use(v),
    Err(e) => handle(e),
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/d907f741102b2b50. Report an issue: GitHub.