charmbracelet/crush · error
%s: --%s expects valid JSON, got %q: %s
Error message
%s: --%s expects valid JSON, got %q: %s
What it means
This error is thrown by parseFlagValue when a flag declared with kind flagJSONAny receives a value that fails json.Unmarshal. Unlike flagJSONObject, any JSON type is accepted (object, array, string, number, bool), but the text must be syntactically valid JSON. The underlying encoding/json error message is appended to help pinpoint the syntax problem.
Source
Thrown at internal/shellconfig/flags.go:173
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)
}
}
// nextArg returns args[i+1], erroring if the flag is missing its value.
func nextArg(args []string, i int, flag string) (string, error) {
if i+1 >= len(args) {
return "", fmt.Errorf("%s: --%s requires a value", args[0], flag)
}
return args[i+1], nil
}
// storeFlag writes a parsed value into target according to spec.op.
func storeFlag(target map[string]any, spec flagSpec, val any) {View on GitHub (pinned to 7944b8e522)
Solutions
- Pipe the value through `jq .` locally to confirm it is valid JSON before passing it.
- Use single quotes around the whole JSON value on POSIX shells so double quotes survive.
- Quote all keys and strings and remove trailing commas; convert YAML/JSON5 to strict JSON.
- Read the appended json error (offset/position) to locate the exact syntax problem.
Example fix
// before
options set --data '{"model": claude-3,}'
// after
options set --data '{"model": "claude-3"}' Defensive patterns
Strategy: validation
Validate before calling
echo "$value" | jq -e . >/dev/null 2>&1 || { echo "flag value is not valid JSON" >&2; exit 2; } Type guard
func isJSON(s string) bool {
var v any
return json.Unmarshal([]byte(s), &v) == nil
} Try / catch
if err := applyFlags(specs, args, start, target, cmd, stderr); err != nil {
if strings.Contains(err.Error(), "expects valid JSON") {
// err embeds the json.Syntax/Unmarshal message; print as-is with hint
fmt.Fprintln(stderr, err, "\nHint: quote the value and validate with 'jq .'")
}
return err
} Prevention
- Round-trip check with `jq .` before invoking the command.
- Use single quotes on POSIX shells; on Windows cmd escape inner double quotes.
- Convert YAML/JSON5 input to strict JSON first (all keys quoted, no trailing commas).
- Never pass bare unquoted words; even strings need JSON quotes: "foo".
When it happens
Trigger: Calling a builtin flag that parses arbitrary JSON (flagJSONAny) with malformed text such as unquoted keys (`{a:1}`), single-quoted strings, unquoted bare words (`foo`), trailing commas, unterminated strings/brackets, or a value the shell partially mangled before it reached the parser.
Common situations: Single quotes inside the JSON conflicting with shell quoting; forgetting that bare words are not JSON (need `"foo"`); copying JSON5/YAML into a JSON flag; Windows cmd where quoting rules differ and inner double quotes get stripped.
Related errors
- %s: --%s expects a JSON object, got %q
- %s: --%s requires a key and value
- %s: --%s requires a value
- failed to load projects: %w
- ${sessionList} Use more characters or the full hash
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/33b02cc1c8d06291.
Report an issue: GitHub.