BoundaryML/baml · error
--json-args must be a JSON object, got: {json}
Error message
--json-args must be a JSON object, got: {json} What it means
`--json-args` must parse to a JSON object (a map of parameter name to value). If the provided JSON is any other shape (array, string, number, boolean, null), `build_args_from_signature_with_context` rejects it, echoing the offending JSON. Arrays/strings are never auto-mapped positionally.
Source
Thrown at baml_language/crates/baml_exec/src/dispatch.rs:210
}
async fn build_args_from_signature_with_context(
engine: &Arc<BexEngine>,
cli_values: HashMap<String, BexExternalValue>,
json_args: Option<&serde_json::Value>,
param_names: &[String],
param_types: &[RuntimeTy],
param_has_default: &[bool],
helper_context: &HelperCallContext,
) -> Result<Vec<BexCallArg>> {
let _ = param_types;
let mut merged: HashMap<String, RawArg> = HashMap::new();
// `--json-args` first (lower priority — CLI overrides).
if let Some(json) = json_args {
let obj = json
.as_object()
.ok_or_else(|| anyhow!("--json-args must be a JSON object, got: {json}"))?;
for (key, value) in obj {
// Re-stringify each field so the engine deserializer takes a
// fresh JSON document. Round-tripping via `to_string` is
// cheaper than implementing a parallel json-value-to-engine
// path; per-arg JSON is typically tiny.
merged.insert(key.clone(), RawArg::JsonText(value.to_string()));
}
}
// Auto-CLI flags override. By this point the clap parser has already
// validated structure (required flags, unknown flags) and converted
// each raw string to a typed primitive — structured types arrive via
// `--json-args` only.
for (key, value) in cli_values {
merged.insert(key, RawArg::Primitive(Box::new(value)));
}
let mut ordered = Vec::with_capacity(param_names.len());View on GitHub (pinned to bd85ce9dee)
Solutions
- Wrap the payload in a JSON object keyed by parameter names: `{"param": value}`.
- If the file contains an array, restructure it to an object or pass the array as the value of an object-typed parameter.
- Validate the file with jq (e.g. `jq type` should print `object`) before passing via `--json-args @file`.
Example fix
// before
baml run myFunc -- --json-args '["a", 1]'
// after
baml run myFunc -- --json-args '{"name": "a", "count": 1}' Defensive patterns
Strategy: validation
Validate before calling
let json: serde_json::Value = serde_json::from_str(&raw)?;
if !json.is_object() {
anyhow::bail!("--json-args must be an object of {param: value}");
} Type guard
fn is_json_object(v: &serde_json::Value) -> bool { v.is_object() } Try / catch
match result {
Err(e) if e.to_string().contains("--json-args must be a JSON object") => {
eprintln!("wrap the payload as an object keyed by parameter names");
}
other => other,
} Prevention
- Always key --json-args payloads by parameter name
- Validate files with `jq type` (expect `object`) before @file usage
- Never pass bare arrays or scalars as --json-args
When it happens
Trigger: Passing `--json-args '[1,2]'`, `--json-args '"hi"'`, or a file/stdin whose content is valid JSON but not an object; the check is `json.as_object()` in dispatch.rs:210.
Common situations: Feeding a top-level JSON array of arguments, forgetting `{}` braces, or pointing `@file` at a file that contains a JSON array instead of a parameter map.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- type `{ty}` can't be passed through auto-CLI; deliver it via
- missing required argument `{name}` (type: {ty}). pass it via
- usage: baml --replace <tmp> <current>
- unknown feedback field(s) {}; only "title" and "description"
- feedback field "{key}" must be a string
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/c4ab5bfac6e5508f.
Report an issue: GitHub.