{"record":{"id":"995feac143e5fe3d","repo":"BoundaryML/baml","slug":"predicate-did-not-evaluate-to-a-boolean","errorCode":null,"errorMessage":"Predicate did not evaluate to a boolean","messagePattern":"Predicate did not evaluate to a boolean","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"engine/baml-lib/baml-core/src/ir/jinja_helpers.rs","lineNumber":92,"sourceCode":"    // In rust string literals, `{` is escaped as `{{`.\n    // So producing the string `{{}}` requires writing the literal `\"{{{{}}}}\"`\n    let template = format!(r#\"{{{{ {} }}}}\"#, expression.0);\n    let args_dict = minijinja::Value::from_serialize(ctx);\n    Ok(env.render_str(&template, &args_dict)?)\n}\n\n// TODO: (Greg) better error handling.\n// TODO: (Greg) Upstream, typecheck the expression.\npub fn evaluate_predicate(\n    this: &BamlValue,\n    predicate_expression: &JinjaExpression,\n) -> Result<bool, anyhow::Error> {\n    let ctx: HashMap<String, minijinja::Value> =\n        HashMap::from([(\"this\".to_string(), minijinja::Value::from_serialize(this))]);\n    match render_expression(predicate_expression, &ctx)?.as_ref() {\n        \"true\" => Ok(true),\n        \"false\" => Ok(false),\n        _ => Err(anyhow::anyhow!(\"Predicate did not evaluate to a boolean\")),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use baml_types::BamlValue;\n\n    use super::*;\n\n    #[test]\n    fn test_render_expressions() {\n        let ctx = vec![\n            (\n                \"a\".to_string(),\n                BamlValue::List(vec![\n                    BamlValue::Int(1),\n                    BamlValue::Int(2),\n                    BamlValue::Int(3),","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-lib/baml-core/src/ir/jinja_helpers.rs#L74-L110","documentation":"BAML constraint predicates (@assert/@check) are Jinja expressions rendered with 'this' bound to the value. The rendered output must be the string \"true\" or \"false\"; anything else raises this error. It ensures predicates are boolean expressions rather than arbitrary values.","triggerScenarios":"Calling evaluate_predicate (directly or via first_failing_assert_nested / run_user_checks) with a predicate expression whose rendered result is neither \"true\" nor \"false\" — e.g. {{ this.name }}, {{ this.items|length }}, or an expression producing an object.","commonSituations":"Writing an @assert that returns the field instead of a comparison; forgetting a comparison operator; using a filter that returns a number/string; predicates like {{ this.email }} intended as 'must be truthy'.","solutions":["Rewrite the predicate to be an explicit boolean comparison, e.g. {{ this.email != \"\" }}.","Avoid predicates that return raw values; wrap them with a comparison or boolean cast.","Test the expression renders exactly 'true' or 'false' for sample inputs."],"exampleFix":"// before\n@assert({{ this.items }})\n// after\n@assert({{ this.items|length > 0 }})","handlingStrategy":"validation","validationCode":"fn is_boolean_predicate(expr: &str) -> bool {\n    // naive guard: reject bare 'this.x' returns without a comparison\n    let comparisons = [\">\", \"<\", \">=\", \"<=\", \"==\", \"!=\", \"&&\", \"||\", \"not \", \"|length >\"];\n    comparisons.iter().any(|c| expr.contains(c))\n}","typeGuard":null,"tryCatchPattern":"match evaluate_predicate(&value, &expr) {\n    Ok(b) => b,\n    Err(e) if e.to_string().contains(\"did not evaluate to a boolean\") => {\n        eprintln!(\"predicate '{}' must be a comparison, got a value\", expr);\n        false\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always write predicates as explicit boolean comparisons.","Never return a raw field or number from @assert/@check.","Sanity-check that the expression renders to exactly 'true' or 'false'."],"tags":["validation","assert","jinja","boolean"],"backgroundTag":"predicate-not-boolean","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"}