BoundaryML/baml · error

Cannot call expr function through call_function_impl

Error message

Cannot call expr function through call_function_impl

What it means

BAML expression functions (`expr`-based functions with no LLM prompt) cannot be executed through `call_function_impl`, which requires a real prepared LLM function with a prompt renderer and orchestration graph. The code explicitly rejects a prepared call whose `func` is None, which is the marker for expression functions.

Source

Thrown at engine/baml-runtime/src/runtime_methods/call_function.rs:53

    },
    runtime_interface::RuntimeConstructor,
    tracing::BamlTracer,
    tracingv2::storage::storage::{Collector, BAML_TRACER},
    type_builder::TypeBuilder,
    BamlRuntime, FunctionResult, FunctionResultStream, InternalRuntimeInterface,
    RenderCurlSettings, RuntimeContext, RuntimeContextManager, TripWire,
};

impl BamlRuntime {
    pub(crate) async fn call_function_impl<'ir>(
        &'ir self,
        prepared_func_call: PreparedFunction<'ir>,
        ctx: RuntimeContext,
        cancel_tripwire: Arc<TripWire>,
    ) -> Result<crate::FunctionResult> {
        let future = async {
            let func = prepared_func_call.func.as_ref().ok_or_else(|| {
                anyhow::anyhow!("Cannot call expr function through call_function_impl")
            })?;
            let renderer = PromptRenderer::from_function(func, self.ir(), &ctx)?;
            let orchestrator = self.orchestration_graph(renderer.client_spec(), &ctx)?;

            let baml_args = BamlValue::Map(prepared_func_call.baml_args.value);

            // Now actually execute the code.
            let (history, _) = orchestrate_call(
                orchestrator,
                self.ir(),
                &ctx,
                &renderer,
                &baml_args,
                |s| renderer.parse(self.ir(), &ctx, s, false),
                cancel_tripwire.trip_wire(),
            )
            .await;

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Route expr functions through the expr-aware path (`call_function_with_expr_events`) instead of `call_function` / call_function_impl.
  2. If the function should be an LLM function, restore its prompt/client definition in the BAML source so it is not treated as an expr function.
  3. Check the function's definition in baml_src: functions whose body is an expression are not streamable/callable via the generic LLM call path.

Example fix

// before
let result = runtime.call_function("my_expr_fn", params).await?; // panics into this error
// after
let result = runtime.call_function_with_expr_events("my_expr_fn", params).await?;
Defensive patterns

Strategy: try-catch

Validate before calling

// Client code: only call generic call_function for LLM (non-expr) functions
if is_expr_function(runtime, "my_fn") {
    return call_function_with_expr_events(runtime, "my_fn", params).await;
}

Try / catch

// Rust
match runtime.call_function("my_fn", params).await {
    Ok(r) => r,
    Err(e) if e.to_string().contains("expr function") => {
        runtime.call_function_with_expr_events("my_fn", params).await?
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Invoking a BAML expr function via the non-expr runtime path (e.g. a client/runtime `call_function` API, or call_function_with_expr_events when the prepared function turns out to be an expr function).

Common situations: A BAML function was refactored from an LLM prompt function into an expr function while client code still calls the generic function-call API; SDK callers using call_function on a function defined purely with `expr`.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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