multica-ai/multica · error
%s must be a JSON object
Error message
%s must be a JSON object
What it means
Thrown by parseMcpJSONObject when the JSON flag value parses to a non-object type and the flag does not allow null (allowNull=false). Only a top-level JSON object is accepted; there is no clear sentinel for this flag, so even the literal null is rejected earlier with a different message. The error is purely client-side shape validation before any request is made.
Source
Thrown at server/cmd/multica/cmd_agent.go:1349
var probe any
if err := json.Unmarshal([]byte(trimmed), &probe); err != nil {
if allowNull {
return nil, fmt.Errorf("%s must be a valid JSON object, or 'null' to clear", flag)
}
return nil, fmt.Errorf("%s must be a valid JSON object", flag)
}
if probe == nil {
if allowNull {
// null → clear (NULL column server-side; on create it is a no-op).
return json.RawMessage("null"), nil
}
return nil, fmt.Errorf("%s must be a JSON object, not null", flag)
}
if _, ok := probe.(map[string]any); !ok {
if allowNull {
return nil, fmt.Errorf("%s must be a JSON object, or 'null' to clear", flag)
}
return nil, fmt.Errorf("%s must be a JSON object", flag)
}
return json.RawMessage(trimmed), nil
}
// resolveMcpConfig collects the --mcp-config, --mcp-config-stdin, and
// --mcp-config-file flags and returns the raw JSON value to send, a bool
// indicating whether the caller supplied any of them, and any error. Mirrors
// resolveCustomEnv; the only behavioural difference is the clear sentinel
// (`null` here vs `{}` for custom_env), because mcp_config distinguishes an
// explicit empty object from an absent config server-side.
func resolveMcpConfig(cmd *cobra.Command) (json.RawMessage, bool, error) {
return resolveMcpJSONObject(cmd, "mcp-config", true)
}
// resolveMcpJSONObject collects the `<prefix>`, `<prefix>-stdin`, and
// `<prefix>-file` flags. The three input channels are mutually exclusive so
// callers can't accidentally provide a secret twice. Stdin and file inputs
// exist to keep payloads — which routinely embed API tokens — out of shellView on GitHub (pinned to 2c0912b6ec)
Solutions
- Change the value so its top-level JSON type is an object (map of keys to values)
- Check the value with jq: echo "$VALUE" | jq -e 'type == "object"' must succeed
- If you meant to clear the field, check that flag's docs — this variant does not accept null; omit the flag or use the flag's documented clear sentinel
Example fix
# before
--mcp-config '["a","b"]'
# after
--mcp-config '{"a": {}, "b": {}}' Defensive patterns
Strategy: validation
Validate before calling
jq -e 'type == "object"' cfg.json >/dev/null || { echo "config must be a JSON object" >&2; exit 1; }
multica agent update <id> --mcp-config-file cfg.json Prevention
- Treat 'JSON object' flags as map-shaped by convention
- Add a CI lint step: jq -e 'type == "object"' on every config file
- Generate configs with a tool that always emits objects, not hand-written JSON
When it happens
Trigger: Any call site that uses resolveMcpJSONObject with allowNull=false (a JSON-object flag without a null clear path) and receives a JSON array, string, number, or boolean as the top-level value.
Common situations: Passing a JSON array where the CLI expects a map; accidentally quoting the JSON so it parses as a string; using a template or env-substituted value that collapses to a scalar.
Related errors
- --runtime-config must be valid JSON: %w
- %s must be a JSON object, or 'null' to clear
- --runtime-config must be valid JSON: %w
- --config must be valid JSON: %w
- body must be a JSON object or array
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/07713daeed5911f5.
Report an issue: GitHub.