BoundaryML/baml · error
c_for_init_stmt cannot accept empty input
Error message
c_for_init_stmt cannot accept empty input
What it means
parse_c_for_loop consumes an optional Rule::c_for_init_stmt in the for-loop header and .next().expect(...)s it is non-empty. A c_for_init_stmt pair with no children is treated as impossible, so it panics with 'c_for_init_stmt cannot accept empty input'.
Source
Thrown at engine/baml-lib/ast/src/parser/parse_expr.rs:199
None
}
}
}
fn parse_c_for_loop(
token: Pair<'_>,
body: ExpressionBlock,
span: Span,
diagnostics: &mut Diagnostics,
) -> Option<CForLoopStmt> {
assert_correct_parser(&token, &[Rule::c_for_loop], diagnostics);
let mut header = token.into_inner();
let init_stmt = consume_if_rule(&mut header, Rule::c_for_init_stmt).map(|rule| {
rule.into_inner()
.next()
.expect("c_for_init_stmt cannot accept empty input")
});
let condition = consume_if_rule(&mut header, Rule::expression);
let after_stmt = consume_if_rule(&mut header, Rule::c_for_after_stmt).map(|rule| {
rule.into_inner()
.next()
.expect("c_for_after_stmt cannot accept empty input")
});
let init_stmt = parse_optional_rule(init_stmt, |rule| {
let span = diagnostics.span(rule.as_span());
parse_statement_inner_rule(rule, span, diagnostics)
})?
.map(Box::new);
let condition = parse_optional_rule(condition, |rule| parse_expression(rule, diagnostics))?;
let after_stmt = parse_optional_rule(after_stmt, |rule| {
let span = diagnostics.span(rule.as_span());View on GitHub (pinned to bd85ce9dee)
Solutions
- Ensure grammar (baml.bsl/pest) and parser code are from the same version.
- Replace .expect with proper error handling (ok_or + anyhow!) if you maintain the crate.
- Report the expression snippet upstream if reproducible on a release.
Example fix
// before
rule.into_inner().next().expect("c_for_init_stmt cannot accept empty input")
// after
rule.into_inner().next().ok_or_else(|| anyhow!("c_for_init_stmt cannot accept empty input"))? Defensive patterns
Strategy: type-guard
Validate before calling
let has_child = header
.clone()
.find(|p| p.as_rule() == Rule::c_for_init_stmt)
.map(|p| p.into_inner().next().is_some())
.unwrap_or(true);
if !has_child {
eprintln!("empty c_for_init_stmt; aborting parse of this loop");
} Type guard
fn init_stmt_present(header: &Pairs<Rule>) -> bool {
header.clone()
.find(|p| p.as_rule() == Rule::c_for_init_stmt)
.map(|p| p.into_inner().next().is_some())
.unwrap_or(true)
} Try / catch
let r = std::panic::catch_unwind(|| parse_c_for_loop(token, &mut diagnostics));
if r.is_err() {
diagnostics.push(format!("unparseable for-loop at {}", token.as_str()));
} Prevention
- Synchronize grammar changes with parse_expr.rs updates in one change.
- Prefer ok_or(anyhow!(...)) over expect when maintaining this code.
- Cover for-loop parsing with snapshot tests after grammar edits.
When it happens
Trigger: Parsing a for-statement whose grammar-produced c_for_init_stmt token has zero inner pairs — a grammar/parse_expr desync (e.g. grammar made init optional internally) when parsing `for ... in ...` expressions with C-style headers.
Common situations: Custom ast crate builds where the expression grammar was modified; rarely on stock releases since the grammar guarantees a child.
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
- c_for_after_stmt cannot accept empty input
- Name should always be defined for attribute.
- Encountered impossible doc comment during parsing: {:?}, {:?
- block aware tail expression is not empty
- Unexpected prefix operator: {:?}
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/9b1b82a746a90a90.
Report an issue: GitHub.