BoundaryML/baml · error

block aware tail expression is not empty

Error message

block aware tail expression is not empty

What it means

This is a Rust panic from an `expect()` inside `parse_block_aware_tail_expression` in the BAML AST parser. The function asserts that a `block_aware_tail_expression` grammar rule always has at least one child pair (`into_inner().next()`); if the pest parse tree produced an empty node, the invariant is broken and the parser panics. It signals a mismatch between the grammar definition (.pest) and the parsing code, not user error in normal cases.

Source

Thrown at engine/baml-lib/ast/src/parser/parse_expr.rs:298

        identifier,
        iterator,
        body,
        span,
        has_let,
        annotations: vec![],
    })
}

fn parse_block_aware_tail_expression(
    pair: Pair<'_>,
    diagnostics: &mut Diagnostics,
) -> Option<Expression> {
    assert_correct_parser(&pair, &[Rule::block_aware_tail_expression], diagnostics);

    let inner = pair
        .into_inner()
        .next()
        .expect("block aware tail expression is not empty");

    match inner.as_rule() {
        Rule::expression => parse_expression(inner, diagnostics),
        Rule::identifier => Some(Expression::Identifier(parse_identifier(inner, diagnostics))),
        _ => {
            unreachable_rule(&inner, "block_aware_tail_expression", diagnostics);
            None
        }
    }
}

/// Lifts the error from `parse` into the top-level optional. The second level optional will
/// reflect whether there was a rule in the first place.
fn parse_optional_rule<T>(
    rule: Option<Pair<'_>>,
    parse: impl FnOnce(Pair<'_>) -> Option<T>,
) -> Option<Option<T>> {
    rule.map_or(Some(None), |rule| parse(rule).map(Some))

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Add a body/tail expression to the while/for/if block that triggered the crash so the rule has at least one child
  2. Check the BAML source around the reported span for an empty block (`{}`) or a truncated expression and complete it
  3. If you are a contributor: tighten the .pest rule (`block_aware_tail_expression` must require ≥1 child) or handle the empty case with diagnostics instead of `expect`
  4. Update baml-cli/baml to a version where this grammar/code mismatch is fixed

Example fix

// before (baml source that panics)
while input != null {}
// after
while input != null {
  output = input
}
Defensive patterns

Strategy: validation

Validate before calling

// Before invoking the parser (or when generating BAML programmatically):
function validateBlockHasBody(blockText) {
  // every while/for/if must have a non-empty body
  const m = blockText.match(/(while|for|if)\s*\([^)]*\)\s*\{\s*\}/);
  if (m) throw new Error(`Empty block body will crash the BAML parser: ${blockText}`);
}

Type guard

const isNonEmptyBlock = (blockText) => !/\{\s*\}\s*$/.test(blockText.trim());

Prevention

When it happens

Trigger: Calling `parse_block_aware_tail_expression` with a Pair whose rule is `block_aware_tail_expression` but which contains no inner pairs — i.e. the grammar accepted an empty block-aware tail expression (e.g. `while cond {}` / `for x in it {}` / `if cond {}` with no body tail in a grammar revision where the rule can match empty input).

Common situations: Developers writing BAML while/for/if blocks whose body is empty and hitting a parser crash instead of a diagnostics message; contributors who modified baml.pest so that `block_aware_tail_expression` can match zero children; running an older/newer grammar with mismatched parser code.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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