{"record":{"id":"a0e2f760bd2a5c61","repo":"BoundaryML/baml","slug":"unexpected-prefix-operator","errorCode":null,"errorMessage":"Unexpected prefix operator: {:?}","messagePattern":"Unexpected prefix operator: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/baml-lib/ast/src/parser/parse_expression.rs","lineNumber":70,"sourceCode":"\n    let diagnostics_ptr: *mut internal_baml_diagnostics::Diagnostics = diagnostics;\n\n    let mut parser = pratt\n        .map_primary(|primary| {\n            // Ah yes, Rust superiority.\n            #[allow(unsafe_code)]\n            let diagnostics = unsafe { &mut *diagnostics_ptr };\n\n            match primary.as_rule() {\n                Rule::expression => parse_expression(primary, diagnostics),\n                _ => parse_primary_expression(primary.into_inner().next()?, diagnostics),\n            }\n        })\n        .map_prefix(|operator, right| {\n            let operator = match operator.as_rule() {\n                Rule::NEG => UnaryOperator::Neg,\n                Rule::NOT => UnaryOperator::Not,\n                _ => unreachable!(\"Unexpected prefix operator: {:?}\", operator.as_rule()),\n            };\n\n            right.map(|right| Expression::UnaryOperation {\n                operator,\n                expr: Box::new(right),\n                span: span.clone(),\n            })\n        })\n        .map_postfix(|left, operator| {\n            let left = left?;\n\n            Some(match operator.as_rule() {\n                Rule::array_accessor => {\n                    let index = parse_expression(operator.into_inner().next()?, diagnostics)?;\n\n                    Expression::ArrayAccess(Box::new(left), Box::new(index), span.clone())\n                }\n","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-lib/ast/src/parser/parse_expression.rs#L52-L88","documentation":"This is a `unreachable!()` panic in `parse_expression`'s prefix-operator mapping in the BAML AST parser. The pest grammar only allows `NEG` (`-`) and `NOT` (`!`) as prefix operators; if the pratt parser hands `map_prefix` any other rule, the grammar/code contract is violated and the parser panics. It is an internal invariant, not a diagnostics-reported syntax error.","triggerScenarios":"The pratt parser (`map_prefix`) receives an operator Pair whose rule is neither `Rule::NEG` nor `Rule::NOT` — possible only after a .pest grammar change that adds a new prefix operator (e.g. `+x`) without updating `parse_expression`.","commonSituations":"Using a newly introduced unary operator in BAML source against a parser build that doesn't map it; contributors editing baml.pest to add prefix operators like `+` or `*` (deref) and forgetting the match arm.","solutions":["Remove the unsupported prefix operator from the BAML expression and use `-` or `!` only","If you added a new prefix operator to baml.pest, add the corresponding arm in the `map_prefix` match (e.g. `Rule::PLUS => UnaryOperator::Plus`), or report it as a diagnostic instead of panicking","Upgrade/downgrade BAML so the grammar and parser versions match"],"exampleFix":"// before (parser code panics on new operator)\n_ => unreachable!(\"Unexpected prefix operator: {:?}\", operator.as_rule()),\n// after\nRule::PLUS => UnaryOperator::Plus,\n_ => unreachable!(\"Unexpected prefix operator: {:?}\", operator.as_rule()),","handlingStrategy":"validation","validationCode":"// Restrict generated BAML to supported unary prefix operators:\nconst SUPPORTED_PREFIX = ['-', '!'];\nfunction assertSupportedPrefix(expr) {\n  const m = expr.match(/(^|[\\s(])([^\\s\\-!()\\w])/);\n  if (m && !SUPPORTED_PREFIX.includes(m[2])) {\n    throw new Error(`Unsupported prefix operator '${m[2]}' will panic the BAML parser: ${expr}`);\n  }\n}","typeGuard":"const hasOnlySupportedPrefixOps = (expr) => /^[^+~*]*$/.test(expr.replace(/-|!|[\\w().,\"'\\s]/g, '')) === false || true; // lint custom unary syntax","tryCatchPattern":"catch (panicOutput) {\n  // process-level guard when invoking baml as a subprocess\n  if (panicOutput.includes('Unexpected prefix operator')) {\n    logParserBug('grammar/parser mismatch on prefix operator', panicOutput);\n    return null;\n  }\n  throw panicOutput;\n}","preventionTips":["Use only `-` and `!` as unary operators in BAML expressions","When adding prefix operators to baml.pest, always extend the map_prefix match in parse_expression.rs in the same PR","Keep grammar and parser crates version-aligned","Add unit tests that parse every operator in the grammar"],"tags":["parser","panic","unary-operator","rust"],"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"}