BoundaryML/baml · error · minijinja::Error

TooManyArguments

TooManyArguments

Error message

role() called with two roles: '{a}' and '{b}'

What it means

BAML's `role()` template function accepts a role either positionally — `role('assistant')` — or as a keyword — `role(role='assistant')`. Supplying both makes the intent ambiguous, so the function immediately returns a TooManyArguments error naming both conflicting roles.

Source

Thrown at engine/baml-lib/jinja-runtime/src/lib.rs:334

    for (enum_name, enum_values) in enum_values_by_name {
        env.add_global(
            enum_name.clone(),
            minijinja::value::Value::from_object(MinijinjaBamlEnumType {
                enum_name,
                enum_values: enum_values
                    .into_iter()
                    .map(|v| (v.value.clone(), v))
                    .collect(),
            }),
        );
    }

    let role_fn = minijinja::Value::from_function(
        |role: Option<String>, kwargs: Kwargs| -> Result<String, minijinja::Error> {
            let role = match (role, kwargs.get::<String>("role")) {
                (Some(b), Ok(a)) => {
                    // If both are present, we should error
                    return Err(minijinja::Error::new(
                        ErrorKind::TooManyArguments,
                        format!("role() called with two roles: '{a}' and '{b}'"),
                    ));
                }
                (Some(role), _) => role,
                (_, Ok(role)) => role,
                _ => {
                    // If neither are present, we should error
                    return Err(minijinja::Error::new(
                        ErrorKind::MissingArgument,
                        "role() called without role. Try role('role') or role(role='role').",
                    ));
                }
            };

            let allow_duplicate_role = match kwargs.get::<bool>("__baml_allow_dupe_role__") {
                Ok(allow_duplicate_role) => allow_duplicate_role,
                Err(e) => match e.kind() {

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Keep exactly one form: either `{{ role('assistant') }}` or `{{ role(role='assistant') }}`.
  2. If a macro/wrapper supplies the role positionally, remove the literal role= kwarg from the template (or vice versa).
  3. Search the template and any included macros for all role() call sites and unify the style.

Example fix

// before
{{ _.role('user', role='system') }}Message

// after
{{ _.role('user') }}Message
Defensive patterns

Strategy: validation

Validate before calling

// reject role() calls mixing positional and kwarg forms during template linting
const bad = /role\s*\(\s*['"][^'"]+['"]\s*,\s*role\s*=/;

Prevention

When it happens

Trigger: A chat template calling `{{ role('user', role='system') }}` or a macro that injects a positional role while the template also passes the `role=` kwarg.

Common situations: Refactoring templates from positional to keyword style and leaving both; composable partial templates where a wrapper passes role positionally and the inner template adds role=; copy-paste merges of two role call styles.

Related errors


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