{"record":{"id":"f31e62828f83c362","repo":"alibaba/open-code-review","slug":"expected-json-object-w","errorCode":null,"errorMessage":"expected JSON object: %w","messagePattern":"expected JSON object: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/opencodereview/config_cmd.go","lineNumber":939,"sourceCode":"\t\t\tfiltered = append(filtered, t)\n\t\t}\n\t\tentry.Tools = filtered\n\tcase \"setup\":\n\t\tentry.Setup = value\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown MCP server field %q: supported fields are type, command, args, env, url, headers, tools, setup\", field)\n\t}\n\n\tcfg.MCPServers[name] = entry\n\treturn nil\n}\n\n// parseMCPHeaders parses a JSON object of header key-value pairs.\n// Example: {\"Authorization\": \"Bearer $TOKEN\", \"X-Custom\": \"value\"}\nfunc parseMCPHeaders(value string) (map[string]string, error) {\n\tvar m map[string]string\n\tif err := json.Unmarshal([]byte(value), &m); err != nil {\n\t\treturn nil, fmt.Errorf(\"expected JSON object: %w\", err)\n\t}\n\tfor k, v := range m {\n\t\tif k == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"header name must not be empty\")\n\t\t}\n\t\tif v == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"header value for %q must not be empty\", k)\n\t\t}\n\t}\n\treturn m, nil\n}\n\nfunc (c *Config) ensureTelemetry() {\n\tif c.Telemetry == nil {\n\t\tc.Telemetry = &TelemetryConfig{}\n\t}\n}\n","sourceCodeStart":921,"sourceCodeEnd":957,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/cmd/opencodereview/config_cmd.go#L921-L957","documentation":"parseMCPHeaders wraps the json.Unmarshal failure with \"expected JSON object: <cause>\" when the headers value cannot be decoded into map[string]string. The headers field must be a flat JSON object whose keys and values are strings; arrays, bare strings, or nested objects fail here, and the error is then surfaced by setMCPServerValue as \"invalid headers for ...\".","triggerScenarios":"`ocr config set mcp-servers.myserver.headers '[\"a\"]'` (array), `'{\"a\": 123}'` (non-string value), or a bare unquoted word; also malformed JSON like a missing brace or unquoted key.","commonSituations":"Non-string header values (numbers/booleans) in the JSON; single quotes inside the JSON unquoted by the shell; forgetting the braces around key-value pairs.","solutions":["Pass a flat JSON object of strings: '{\"Authorization\":\"Bearer t\"}'","Quote all JSON keys and ensure values are strings (use \"123\" not 123)","Read the wrapped json error after `expected JSON object:` for the exact offset"],"exampleFix":"// before\nocr config set mcp-servers.myserver.headers '{\"X-Retries\": 3}'\n// after\nocr config set mcp-servers.myserver.headers '{\"X-Retries\": \"3\"}'","handlingStrategy":"validation","validationCode":"func validHeaderObject(s string) bool {\n    var m map[string]string\n    return json.Unmarshal([]byte(s), &m) == nil\n}","typeGuard":"func asHeaderMap(v any) (map[string]string, bool) { m, ok := v.(map[string]string); return m, ok }","tryCatchPattern":"_, err := parseMCPHeaders(raw)\nif err != nil {\n    var se *json.SyntaxError\n    if errors.As(err, &se) { fmt.Fprintf(os.Stderr, \"bad JSON at offset %d\", se.Offset) }\n    return err\n}","preventionTips":["Ensure all JSON keys are quoted and values are strings","Pipe the candidate value through `jq type` to confirm it is an object","Avoid nested header values — flatten to strings first"],"tags":["json","config","validation","mcp"],"backgroundTag":"invalid-json-input","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}