BoundaryML/baml · error · anyhow::Error

args must be a map

Error message

args must be a map

What it means

The public render_prompt entry point requires its `args` parameter (the variables exposed to the template) to be a BamlValue::Map. Any other BamlValue variant — list, string, null, etc. — is rejected immediately with this anyhow bail before any rendering happens.

Source

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

//                 minijinja_err += &format!("\n\ncaused by: {next_err:#}");
//                 err = next_err;
//             }

//             anyhow::bail!("Error occurred while rendering prompt: {minijinja_err}");
//         }
//     }
// }

pub fn render_prompt(
    template: &str,
    args: &BamlValue,
    ctx: RenderContext,
    template_string_macros: &[TemplateStringMacro],
    ir: &IntermediateRepr,
    env_vars: &HashMap<String, String>,
) -> anyhow::Result<RenderedPrompt> {
    if !matches!(args, BamlValue::Map(_)) {
        anyhow::bail!("args must be a map");
    }
    let eval_ctx = EvaluationContext::new(env_vars, false);
    let minijinja_args: minijinja::Value = args.clone().to_minijinja_value(ir, &eval_ctx);
    let default_role = ctx.client.default_role.clone();
    let allowed_roles = ctx.client.allowed_roles.clone();
    let remap_role = ctx.client.remap_role.clone();
    let enum_values_by_name = ir
        .walk_enums()
        .map(|e| {
            let enum_name = e.name().to_string();
            let enum_values = e
                .walk_values()
                .map(|v| MinijinjaBamlEnumValue {
                    value: v.name().to_string(),
                    alias: v.alias(&eval_ctx).unwrap_or(None),
                    enum_name: enum_name.clone(),
                })
                .collect::<Vec<_>>();

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Wrap template variables in a named map: {"var1": value1, "var2": value2} before calling render_prompt.
  2. If args come from JSON, ensure the top level is an object `{...}`, not an array or scalar.
  3. Check helper wrappers (render_chat, render_completion) to confirm they are passed a map, not raw values.

Example fix

// before
let args = BamlValue::List(vec![...]);
render_prompt(ctx, &args, ...)

// after
let args = BamlValue::Map(vec![("name".into(), BamlValue::String("world".into()))].into_iter().collect());
render_prompt(ctx, &args, ...)
Defensive patterns

Strategy: type-guard

Validate before calling

// ensure args is a map/object before calling render_prompt
if (args === null || typeof args !== "object" || Array.isArray(args)) throw new Error("args must be a named map of template variables");

Type guard

function isArgsMap(v) { return v !== null && typeof v === "object" && !Array.isArray(v); }

Try / catch

match render_prompt(ctx, &args, ...) { Err(e) if e.to_string().contains("args must be a map") => { /* fix caller */ }, Err(e) => return Err(e) }

Prevention

When it happens

Trigger: Calling render_prompt (directly or via render_chat/render_completion/render_image helpers) with args constructed as a non-map BamlValue, or passing null/None where a map of named template variables is expected.

Common situations: Programmatic/SDK use where args are built dynamically and end up as a list or scalar; forgetting to wrap variables in a named map; deserializing args from JSON that is an array rather than an object.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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