BoundaryML/baml · error
! operator requires boolean operand at
Error message
! operator requires boolean operand at {:?} What it means
Thrown when the unary `!` (logical not) operator is applied to a value that is not a Bool at runtime. The interpreter only implements Not for BamlValueWithMeta::Bool; all other variants bail. BAML does not implicitly truthiness-coerce values like JavaScript does.
Solutions
- Ensure the operand of ! is a boolean expression; add an explicit comparison, e.g. `!(x == 0)` instead of `!x`
- Annotate the variable as bool so the typechecker catches non-bool values before interpretation
- Convert truthiness manually, e.g. `x == null` or `x == ""` rather than `!x`
- If the value is optional, unwrap/coalesce it to a bool first (`x ?? false`)
Example fix
// before (BAML) let disabled = !retries; // retries: int // after let disabled = !(retries > 0);
Defensive patterns
Strategy: type-guard
Validate before calling
// ensure the operand is boolean before negation
if (typeof flag !== 'boolean') {
throw new Error(`! requires bool, got ${typeof flag}`);
} Type guard
const isBool = (v: unknown): v is boolean => typeof v === 'boolean';
Try / catch
try {
result = evaluate(expr);
} catch (e) {
if (String(e).includes('! operator requires boolean operand')) {
// rewrite as explicit comparison
}
throw e;
} Prevention
- Never rely on truthiness; write explicit comparisons
- Annotate flags as bool in BAML schemas
- Coalesce optionals before negation (x ?? false)
When it happens
Trigger: Evaluating `!x` where `x` is an int, float, string, null, list, or class instance instead of a bool. Common with values flowing from JSON parsing, optional fields, or function returns typed loosely.
Common situations: Negating a comparison result that was accidentally omitted (`!x` instead of `!(x == y)`), negating an optional/int flag from config, or applying ! to a string in a prompt-expression.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- - operator requires numeric operand at
- array assignment index out of bounds
- array assignment on non-list value at
- array assignment requires a non-negative integer index at
- assign to undeclared variable
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/91167b4f892fbbf5.
Report an issue: GitHub.
Appendix: source
Thrown at engine/baml-compiler/src/thir/interpret.rs:2546
BinaryOperator::InstanceOf => match (left_val.clone(), right_val.clone()) {
(BamlValueWithMeta::Class(class, ..), BamlValueWithMeta::Class(right_class, ..)) => {
BamlValueWithMeta::Bool(class == right_class, meta.clone())
}
_ => bail!("instanceof requires class operands at {:?}", meta.0),
},
})
}
fn evaluate_unary_op(
operator: &crate::hir::UnaryOperator,
val: &BamlValueWithMeta<ExprMetadata>,
meta: &ExprMetadata,
) -> Result<BamlValueWithMeta<ExprMetadata>> {
use crate::hir::UnaryOperator;
Ok(match operator {
UnaryOperator::Not => match val.clone() {
BamlValueWithMeta::Bool(b, _) => BamlValueWithMeta::Bool(!b, meta.clone()),
_ => bail!("! operator requires boolean operand at {:?}", meta.0),
},
UnaryOperator::Neg => match val.clone() {
BamlValueWithMeta::Int(i, _) => BamlValueWithMeta::Int(-i, meta.clone()),
BamlValueWithMeta::Float(f, _) => BamlValueWithMeta::Float(-f, meta.clone()),
_ => bail!("- operator requires numeric operand at {:?}", meta.0),
},
})
}
fn values_equal(
left: &BamlValueWithMeta<ExprMetadata>,
right: &BamlValueWithMeta<ExprMetadata>,
) -> bool {
match (left, right) {
(BamlValueWithMeta::Int(a, _), BamlValueWithMeta::Int(b, _)) => a == b,
(BamlValueWithMeta::Float(a, _), BamlValueWithMeta::Float(b, _)) => a == b,
(BamlValueWithMeta::Int(a, _), BamlValueWithMeta::Float(b, _)) => *a as f64 == *b,
(BamlValueWithMeta::Float(a, _), BamlValueWithMeta::Int(b, _)) => *a == *b as f64,View on GitHub (pinned to bd85ce9dee)