BoundaryML/baml · error

break statement not in loop context

Error message

break statement not in loop context

What it means

Raised by evaluate_block, the wrapper that evaluates a BAML block where break/continue are not meaningful. If the block (or a nested block) executes a `break` and the ControlFlow::Break value propagates all the way out to a context that is not a loop (e.g. a filter/lambda function body or a plain expression evaluation), the interpreter rejects it with this error.

Solutions

  1. Remove the `break` or ensure it is placed directly inside a for/while loop body.
  2. If inside a lambda/filter function, use `return` (or the block's trailing expression) instead of `break` to stop processing.
  3. Restructure the logic with an if condition around the loop-body work instead of breaking out of a non-loop block.
  4. Upgrade BAML if you expect break to be valid in this context (it may be a scoping bug worth reporting).

Example fix

// before (BAML)
let evens = nums.filter(|n| { if (n % 2 != 0) { break; }; n * 2 });
// after
let evens = nums.filter(|n| n % 2 == 0).map(|n| n * 2);
Defensive patterns

Strategy: validation

Validate before calling

// Static guard: `break` must appear inside a loop body in your BAML sources.
// In a filter/lambda callback, reject any break/continue entirely:
if (/\bbreak\b/.test(lambdaBodySrc)) {
  throw new Error("break is not allowed in non-loop blocks; use the predicate or return instead");
}

Try / catch

try {
  return await bamlFn(ctx, args);
} catch (e) {
  if (String(e).includes("break statement not in loop context")) {
    throw new Error("BAML source error: move `break` inside a for loop body");
  }
  throw e;
}

Prevention

When it happens

Trigger: Using `break` inside a BAML block that is not a loop body — e.g. inside a filter/lambda function, an if-else block at the top level of an expression, or a function body — where no loop is on the control-flow stack.

Common situations: Copy-pasting loop code containing `break` into a map/filter callback or an if branch; thinking `break` exits an if block; BAML version where break support exists only in for/while loops.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at engine/baml-compiler/src/thir/interpret.rs:1417

    function_name: &str,
) -> Result<BamlValueWithMeta<ExprMetadata>>
where
    F: LlmHandler<Fut>,
    Fut: LlmFuture,
{
    match evaluate_block_with_control_flow(
        block,
        scopes,
        thir,
        run_llm_function,
        watch_handler,
        function_name,
    )
    .await?
    {
        ControlFlow::Normal(val) => Ok(val),
        ControlFlow::Return(val) => Ok(val),
        ControlFlow::Break => bail!("break statement not in loop context"),
        ControlFlow::Continue => bail!("continue statement not in loop context"),
    }
}

fn declare(scopes: &mut [Scope], name: &str, value: BamlValueWithMeta<ExprMetadata>) {
    if let Some(scope) = scopes.last_mut() {
        scope
            .variables
            .insert(name.to_string(), Arc::new(Mutex::new(value)));
    }
}

fn declare_with_cell(
    scopes: &mut [Scope],
    name: &str,
    cell: Arc<Mutex<BamlValueWithMeta<ExprMetadata>>>,
) {
    if let Some(scope) = scopes.last_mut() {

View on GitHub (pinned to bd85ce9dee)