BoundaryML/baml · error · anyhow::Error

Expression functions must have return type.

Error message

Expression functions must have return type.

What it means

While building the IR Function struct from an AST expression function, the return type annotation must be present. BAML raises this error when expr_fn().return_type is None while converting parameters and constructing the function's representation. Note the slightly different wording ('return type.') distinguishes it from the Arrow-type path at line 251.

Source

Thrown at engine/baml-lib/baml-core/src/ir/repr.rs:290

        Ok(expr_fn)
    }
}

impl WithRepr<Function> for ExprFnWalker<'_> {
    fn repr(&self, db: &ParserDatabase) -> Result<Function> {
        let body = convert_function_body(self.expr_fn().body.to_owned(), db)?;
        let args = self
            .expr_fn()
            .args
            .args
            .iter()
            .map(|(arg_name, arg_type)| Ok((arg_name.to_string(), arg_type.field_type.repr(db)?)))
            .collect::<Result<_>>()?;
        let return_type = self
            .expr_fn()
            .return_type
            .as_ref()
            .ok_or(anyhow::anyhow!(
                "Expression functions must have return type."
            ))?
            .repr(db)?;
        let function = Function {
            name: self.expr_fn().name.to_string(),
            inputs: args,
            output: return_type,
            configs: vec![],
            default_config: "".to_string(),
            tests: vec![],
        };
        Ok(function)
    }
}

/// Convert a function body to an expression.
///
/// The function body is a list of statements, which are let bindings.

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Add an explicit `-> Type` return annotation to the offending fn definition.
  2. Regenerate the client (baml generate) after fixing the annotation.
  3. Synchronize BAML schema versions across your team and CI.

Example fix

// before
fn ExtractName(text string) {
  llm ExtractNamePrompt(text)
}
// after
fn ExtractName(text string) -> string {
  llm ExtractNamePrompt(text)
}
Defensive patterns

Strategy: validation

Validate before calling

# ensure every top-level fn has an explicit return annotation
import re
for m in re.finditer(r'^\s*fn\s+(\w+)\s*\([^)]*\)\s*(->\s*[\w<>\[\]]+)?', src, re.M):
    if not m.group(2):
        print(f"fn {m.group(1)} is missing a return type")

Try / catch

match field_repr(db) {
    Ok(f) => f,
    Err(e) if e.to_string().contains("must have return type") => {
        eprintln!("fix the fn lacking `-> ReturnType` in the .baml schema");
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: repr(db) on a top-level expression function definition missing `-> ReturnType`; triggered during IR construction for functions used in client codegen.

Common situations: Expression functions declared without return annotations; migrated/copied BAML functions where the return type line was dropped; mixed BAML versions across team members.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/94764394a3e77948. Report an issue: GitHub.