{"record":{"id":"9b1b82a746a90a90","repo":"BoundaryML/baml","slug":"c-for-init-stmt-cannot-accept-empty-input","errorCode":null,"errorMessage":"c_for_init_stmt cannot accept empty input","messagePattern":"c_for_init_stmt cannot accept empty input","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/baml-lib/ast/src/parser/parse_expr.rs","lineNumber":199,"sourceCode":"            None\n        }\n    }\n}\n\nfn parse_c_for_loop(\n    token: Pair<'_>,\n    body: ExpressionBlock,\n    span: Span,\n    diagnostics: &mut Diagnostics,\n) -> Option<CForLoopStmt> {\n    assert_correct_parser(&token, &[Rule::c_for_loop], diagnostics);\n\n    let mut header = token.into_inner();\n\n    let init_stmt = consume_if_rule(&mut header, Rule::c_for_init_stmt).map(|rule| {\n        rule.into_inner()\n            .next()\n            .expect(\"c_for_init_stmt cannot accept empty input\")\n    });\n    let condition = consume_if_rule(&mut header, Rule::expression);\n    let after_stmt = consume_if_rule(&mut header, Rule::c_for_after_stmt).map(|rule| {\n        rule.into_inner()\n            .next()\n            .expect(\"c_for_after_stmt cannot accept empty input\")\n    });\n\n    let init_stmt = parse_optional_rule(init_stmt, |rule| {\n        let span = diagnostics.span(rule.as_span());\n        parse_statement_inner_rule(rule, span, diagnostics)\n    })?\n    .map(Box::new);\n\n    let condition = parse_optional_rule(condition, |rule| parse_expression(rule, diagnostics))?;\n\n    let after_stmt = parse_optional_rule(after_stmt, |rule| {\n        let span = diagnostics.span(rule.as_span());","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-lib/ast/src/parser/parse_expr.rs#L181-L217","documentation":"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'.","triggerScenarios":"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.","commonSituations":"Custom ast crate builds where the expression grammar was modified; rarely on stock releases since the grammar guarantees a child.","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."],"exampleFix":"// before\nrule.into_inner().next().expect(\"c_for_init_stmt cannot accept empty input\")\n// after\nrule.into_inner().next().ok_or_else(|| anyhow!(\"c_for_init_stmt cannot accept empty input\"))?","handlingStrategy":"type-guard","validationCode":"let has_child = header\n    .clone()\n    .find(|p| p.as_rule() == Rule::c_for_init_stmt)\n    .map(|p| p.into_inner().next().is_some())\n    .unwrap_or(true);\nif !has_child {\n    eprintln!(\"empty c_for_init_stmt; aborting parse of this loop\");\n}","typeGuard":"fn init_stmt_present(header: &Pairs<Rule>) -> bool {\n    header.clone()\n        .find(|p| p.as_rule() == Rule::c_for_init_stmt)\n        .map(|p| p.into_inner().next().is_some())\n        .unwrap_or(true)\n}","tryCatchPattern":"let r = std::panic::catch_unwind(|| parse_c_for_loop(token, &mut diagnostics));\nif r.is_err() {\n    diagnostics.push(format!(\"unparseable for-loop at {}\", token.as_str()));\n}","preventionTips":["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."],"tags":["rust","parser","panic","for-loop","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}