multica-ai/multica · error
%s must be a JSON object, or 'null' to clear
Error message
%s must be a JSON object, or 'null' to clear
What it means
Thrown by parseMcpJSONObject in the multica CLI when a JSON flag value (e.g. --mcp-config) parses successfully but is neither a JSON object nor null, while the flag allows the 'null' clear sentinel. The CLI only accepts a top-level object (or the literal null to clear the stored value); arrays, strings, numbers, and booleans are rejected before any API call. This is a client-side shape validation, so nothing reaches the server.
Source
Thrown at server/cmd/multica/cmd_agent.go:1347
return nil, fmt.Errorf("%s: empty input; pass a JSON object", flag)
}
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 soView on GitHub (pinned to 2c0912b6ec)
Solutions
- Wrap the value in a JSON object, e.g. --mcp-config '{"servers": [...]}' or an object keyed by server name
- If the goal is to clear the stored mcp_config, pass the literal null: --mcp-config 'null'
- Verify the payload shape first with: echo '<json>' | jq 'type' — it must print "object"
Example fix
# before
multica agent update <id> --mcp-config '["fetch", "fs"]'
# after
multica agent update <id> --mcp-config '{"fetch": {"command": "npx", "args": ["-y", "mcp-server-fetch"]}}' Defensive patterns
Strategy: validation
Validate before calling
# before invoking the CLI, confirm top-level type is object (or null)
echo "$CFG" | jq -e 'type == "object" or (.) == null' >/dev/null || { echo "bad mcp-config"; exit 1; }
multica agent update <id> --mcp-config "$CFG" Prevention
- Keep MCP configs as objects keyed by server name, never arrays
- Validate payloads with jq 'type' before passing them to the CLI
- Store config files under version control and lint them in CI with jq -e 'type == "object"'
When it happens
Trigger: Running e.g. `multica agent update <id> --mcp-config '["server1"]'` or `--mcp-config '"hello"'` — any call to agent create/update/copy where resolveMcpConfig(cmd) (allowNull=true) receives valid JSON whose top-level value is not an object and not null.
Common situations: Users pasting a JSON array of server entries instead of an object keyed by server name; wrapping the config in quotes incorrectly so it parses as a string; feeding a config exported from a tool that emits an array.
Related errors
- --runtime-config must be valid JSON: %w
- %s must be a JSON object
- --runtime-config must be valid JSON: %w
- --config must be valid JSON: %w
- one of --server-config, --server-config-stdin, or --server-c
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/5714527bdfa5a901.
Report an issue: GitHub.