{"record":{"id":"8be0ac07e582fa41","repo":"BoundaryML/baml","slug":"use-last-expr-as-return-is-true-but-last-statement-is-not","errorCode":null,"errorMessage":"use_last_expr_as_return is true but last statement is not Expression","messagePattern":"use_last_expr_as_return is true but last statement is not Expression","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/baml-compiler/src/thir/interpret.rs","lineNumber":1382,"sourceCode":"                .await?,\n            )?\n        } else if use_last_expr_as_return {\n            // No explicit trailing expression, but last statement is an expression statement,\n            // so use that as the implicit return value (handles cases like if-else at the end of a block)\n            if let Some(Statement::Expression { expr, .. }) = block.statements.last() {\n                expect_value(\n                    evaluate_expr(\n                        expr,\n                        scopes,\n                        thir,\n                        run_llm_function,\n                        watch_handler,\n                        function_name,\n                    )\n                    .await?,\n                )?\n            } else {\n                unreachable!(\"use_last_expr_as_return is true but last statement is not Expression\")\n            }\n        } else {\n            // No trailing expression and last statement is not an expression, return null\n            BamlValueWithMeta::Null((internal_baml_diagnostics::Span::fake(), None))\n        };\n        scopes.pop();\n        Ok(ControlFlow::Normal(ret))\n    })\n}\n\nasync fn evaluate_block<F, Fut>(\n    block: &Block<ExprMetadata>,\n    scopes: &mut Vec<Scope>,\n    thir: &THir<ExprMetadata>,\n    run_llm_function: &mut F,\n    watch_handler: &SharedWatchHandler,\n    function_name: &str,\n) -> Result<BamlValueWithMeta<ExprMetadata>>","sourceCodeStart":1364,"sourceCodeEnd":1400,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-compiler/src/thir/interpret.rs#L1364-L1400","documentation":"This is an internal invariant violation (an `unreachable!()` panic) in evaluate_block_with_control_flow. The flag use_last_expr_as_return is only supposed to be set when the block's last statement is an Expression statement; if the last statement is anything else (assignment, loop, return, etc.) while the flag is still set, the interpreter panics with this message. It indicates a compiler/interpreter bug, not user error.","triggerScenarios":"A BAML expression block evaluated with implicit-return semantics (use_last_expr_as_return=true) whose final statement is not an Expression — e.g. a block ending in an assignment, a for loop, or a watch statement where the compiler incorrectly enabled implicit return. Also occurs when an early `return` inside the block drains the statement list unexpectedly.","commonSituations":"Hitting this while using newer BAML expression-language features (blocks with implicit returns, if-else as final statement) on code shapes the interpreter doesn't yet handle; usually reported as a bug after upgrading the BAML version.","solutions":["Add an explicit final expression (or explicit `return`) as the last statement of the block so the implicit-return path is entered only with an Expression last statement.","Check for a trailing non-expression statement (assignment, loop) at the end of the block and move or restructure it.","Pin/downgrade to the previous BAML version if this appeared after an upgrade, and file a bug with the minimal reproducing BAML code.","Upgrade to the latest BAML — this unreachable path may already be fixed."],"exampleFix":"// before (BAML)\nlet r = if (x) { total += 1 } else { 0 };\n// after\nlet r = if (x) { total += 1; total } else { 0 };","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// This is an internal panic; catch broadly and degrade:\ntry {\n  return await bamlFn(ctx, args);\n} catch (e) {\n  if (String(e).includes(\"use_last_expr_as_return\")) {\n    logBug(\"baml interpreter invariant violation — file a bug with this input\");\n    return legacyPath(args);\n  }\n  throw e;\n}","preventionTips":["End expression blocks with an explicit expression, never an assignment or loop.","Add explicit `return`/final expression in blocks relying on implicit returns.","Pin your BAML version and test expression blocks after upgrades.","Report this panic upstream with a minimal reproducer — it is a compiler bug."],"tags":["baml","internal-bug","panic","interpreter"],"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"}