charmbracelet/crush · error

%s: --%s expects a JSON object, got %q

Error message

%s: --%s expects a JSON object, got %q

What it means

This error is thrown by parseFlagValue when a flag declared with kind flagJSONObject receives a value that is not valid JSON or does not unmarshal into a JSON object (map[string]any). The check `err != nil || object == nil` also rejects bare `null` and, because the target type is a map, any array, string, number, or boolean. It exists so flags like --provider-options only accept object-shaped JSON that can be merged into a child map.

Source

Thrown at internal/shellconfig/flags.go:162

		if err != nil {
			return nil, 0, fmt.Errorf("%s: --%s expects a number, got %q", args[0], name, v)
		}
		return f, i + 2, nil

	case flagKeyValue:
		if i+2 >= len(args) {
			return nil, 0, fmt.Errorf("%s: --%s requires a key and value", args[0], name)
		}
		return [2]string{args[i+1], args[i+2]}, i + 3, nil

	case flagJSONObject:
		v, err := nextArg(args, i, name)
		if err != nil {
			return nil, 0, err
		}
		var object map[string]any
		if err := json.Unmarshal([]byte(v), &object); err != nil || object == nil {
			return nil, 0, fmt.Errorf("%s: --%s expects a JSON object, got %q", args[0], name, v)
		}
		return object, i + 2, nil

	case flagJSONAny:
		v, err := nextArg(args, i, name)
		if err != nil {
			return nil, 0, err
		}
		var parsed any
		if err := json.Unmarshal([]byte(v), &parsed); err != nil {
			return nil, 0, fmt.Errorf("%s: --%s expects valid JSON, got %q: %s", args[0], name, v, err)
		}
		return parsed, i + 2, nil

	default:
		return nil, 0, fmt.Errorf("%s: --%s has unknown flag kind", args[0], name)
	}
}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Validate the value parses as a JSON object first: `echo '<value>' | jq -e 'type == "object"'`.
  2. Quote the entire JSON blob in single quotes so the shell does not strip braces or double quotes.
  3. Use double quotes for all JSON keys and string values, no trailing commas: `'{"temperature": 0.5}'`.
  4. If passing non-object JSON, use the appropriate flag that accepts arbitrary JSON instead of the object-typed flag.

Example fix

// before
provider add x --provider-options '{temperature: 0.5,}'
// after
provider add x --provider-options '{"temperature": 0.5}'
Defensive patterns

Strategy: validation

Validate before calling

echo "$value" | jq -e 'type == "object"' >/dev/null || { echo "flag value must be a JSON object" >&2; exit 2; }

Type guard

func isJSONObject(s string) bool {
    var m map[string]any
    return json.Unmarshal([]byte(s), &m) == nil && m != nil
}

Try / catch

if err := applyFlags(specs, args, start, target, cmd, stderr); err != nil {
    if strings.Contains(err.Error(), "expects a JSON object") {
        fmt.Fprintln(stderr, "Value must be a JSON object like '{\"key\": 1}', not an array or scalar")
    }
    return err
}

Prevention

When it happens

Trigger: Calling a builtin flag like --provider-options with a value that is invalid JSON (e.g. `{api_key: x}` with unquoted keys, single quotes, trailing commas), a JSON array (`[1,2]`), a bare scalar (`"foo"`, `42`, `true`), or the literal `null`.

Common situations: Hand-writing provider options with unquoted keys or Python-style True/False; shell stripping double quotes (typing --provider-options '{"a":1}' without proper quoting so the shell eats braces/quotes); passing a JSON array where an object is expected; copying JSON with trailing commas.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/ed33e2fea50d2434. Report an issue: GitHub.