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
- Remove the `break` or ensure it is placed directly inside a for/while loop body.
- If inside a lambda/filter function, use `return` (or the block's trailing expression) instead of `break` to stop processing.
- Restructure the logic with an if condition around the loop-body work instead of breaking out of a non-loop block.
- 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
- Use `break` only directly inside for/while loop bodies.
- In map/filter callbacks, filter first or use the predicate — never break.
- Lint BAML sources for break/continue outside loop bodies.
- Remember `break` exits loops, not if-blocks or function bodies.
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
- continue statement not in loop context
- unsupported assign op in C-for after clause
- unsupported statement type in C-for after clause
- {0:?}
- {0}
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)