{"record":{"id":"07713daeed5911f5","repo":"multica-ai/multica","slug":"s-must-be-a-json-object","errorCode":null,"errorMessage":"%s must be a JSON object","messagePattern":"(.+?) must be a JSON object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/multica/cmd_agent.go","lineNumber":1349,"sourceCode":"\tvar probe any\n\tif err := json.Unmarshal([]byte(trimmed), &probe); err != nil {\n\t\tif allowNull {\n\t\t\treturn nil, fmt.Errorf(\"%s must be a valid JSON object, or 'null' to clear\", flag)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"%s must be a valid JSON object\", flag)\n\t}\n\tif probe == nil {\n\t\tif allowNull {\n\t\t\t// null → clear (NULL column server-side; on create it is a no-op).\n\t\t\treturn json.RawMessage(\"null\"), nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"%s must be a JSON object, not null\", flag)\n\t}\n\tif _, ok := probe.(map[string]any); !ok {\n\t\tif allowNull {\n\t\t\treturn nil, fmt.Errorf(\"%s must be a JSON object, or 'null' to clear\", flag)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"%s must be a JSON object\", flag)\n\t}\n\treturn json.RawMessage(trimmed), nil\n}\n\n// resolveMcpConfig collects the --mcp-config, --mcp-config-stdin, and\n// --mcp-config-file flags and returns the raw JSON value to send, a bool\n// indicating whether the caller supplied any of them, and any error. Mirrors\n// resolveCustomEnv; the only behavioural difference is the clear sentinel\n// (`null` here vs `{}` for custom_env), because mcp_config distinguishes an\n// explicit empty object from an absent config server-side.\nfunc resolveMcpConfig(cmd *cobra.Command) (json.RawMessage, bool, error) {\n\treturn resolveMcpJSONObject(cmd, \"mcp-config\", true)\n}\n\n// resolveMcpJSONObject collects the `<prefix>`, `<prefix>-stdin`, and\n// `<prefix>-file` flags. The three input channels are mutually exclusive so\n// callers can't accidentally provide a secret twice. Stdin and file inputs\n// exist to keep payloads — which routinely embed API tokens — out of shell","sourceCodeStart":1331,"sourceCodeEnd":1367,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/multica/cmd_agent.go#L1331-L1367","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\n--mcp-config '[\"a\",\"b\"]'\n# after\n--mcp-config '{\"a\": {}, \"b\": {}}'","handlingStrategy":"validation","validationCode":"jq -e 'type == \"object\"' cfg.json >/dev/null || { echo \"config must be a JSON object\" >&2; exit 1; }\nmultica agent update <id> --mcp-config-file cfg.json","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["cli","json","validation","go"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}