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 shell

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Change the value so its top-level JSON type is an object (map of keys to values)
  2. Check the value with jq: echo "$VALUE" | jq -e 'type == "object"' must succeed
  3. 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

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


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/07713daeed5911f5. Report an issue: GitHub.