{"record":{"id":"b5135719ab11a05b","repo":"BoundaryML/baml","slug":"expected-a-got-a","errorCode":null,"errorMessage":"Expected a {:?}, got a {:?} ({}:{})","messagePattern":"Expected a (.+?), got a (.+?) \\((.+?):(.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/baml-lib/ast/src/formatter/mod.rs","lineNumber":60,"sourceCode":"\n    let doc = formatter.schema_to_doc(schema_pair.into_inner())?;\n    let mut w = Vec::new();\n    doc.render(10, &mut w)\n        .map_err(|_| anyhow!(\"Failed to render doc\"))?;\n    String::from_utf8(w).map_err(|_| anyhow!(\"Failed to convert to string\"))\n}\n\nmacro_rules! next_pair {\n    ($pairs:ident, $rule:expr) => {{\n        loop {\n            match $pairs.peek() {\n                Some(pair) => {\n                    if pair.as_rule() == Rule::NEWLINE {\n                        $pairs.next();\n                        continue;\n                    }\n                    if pair.as_rule() != $rule {\n                        break Err(anyhow!(\n                            \"Expected a {:?}, got a {:?} ({}:{})\",\n                            $rule,\n                            pair.as_rule(),\n                            file!(),\n                            line!()\n                        ));\n                    } else {\n                        $pairs.next();\n                        break Ok(pair);\n                    }\n                }\n                None => break Err(anyhow!(\"Expected a {}\", stringify!($rule))),\n            }\n        }\n    }};\n\n    ($pairs:ident, $rule:expr, optional) => {{\n        match $pairs.peek() {","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-lib/ast/src/formatter/mod.rs#L42-L78","documentation":"The next_pair! macro asserts the next pest pair matches an expected Rule, skipping NEWLINE pairs. On mismatch it errors with 'Expected a {:?}, got a {:?} (file:line)'. It is a formatter-side structural invariant check on the parse tree.","triggerScenarios":"Any format_schema invocation where the pest parse tree shape deviates from what the formatter's macro expects — e.g. grammar changed but formatter macros not updated, or a rule matched in an unexpected position.","commonSituations":"Using a BAML grammar/parser version mismatched with the formatter, or formatting source with syntax that parses but in an ordering the formatter didn't anticipate.","solutions":["Pin the baml ast/parser and formatter to matching versions (same crate release).","Check the reported rule name in the message to locate the offending syntax in your .baml file and simplify it.","Report a bug with the offending schema snippet if versions match — it is a grammar/formatter desync."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match format_schema(source, &options) {\n    Ok(f) => f,\n    Err(e) if e.to_string().starts_with(\"Expected a \") => {\n        eprintln!(\"formatter/grammar desync: {e}\");\n        source.to_string()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Keep parser and formatter crates on the same released version.","Run baml-cli parse before formatting in CI to catch grammar issues early.","Minimize exotic syntax in .baml files until the formatter supports it."],"tags":["rust","parser","formatting","grammar-mismatch"],"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-23T08:17:48.524Z"}