{"record":{"id":"24e7ff48a5ec6668","repo":"alibaba/open-code-review","slug":"parse-app-config-w","errorCode":null,"errorMessage":"parse app config: %w","messagePattern":"parse app config: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/opencodereview/config_cmd.go","lineNumber":412,"sourceCode":"\tvar cfg Config\n\tif err := json.Unmarshal(data, &cfg); err != nil {\n\t\treturn nil, fmt.Errorf(\"parse config: %w\", err)\n\t}\n\treturn &cfg, nil\n}\n\n// LoadAppConfig loads config from path. Returns nil, nil if file does not exist.\nfunc LoadAppConfig(path string) (*Config, error) {\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"read app config %s: %w\", path, err)\n\t}\n\tvar cfg Config\n\tif err := json.Unmarshal(data, &cfg); err != nil {\n\t\treturn nil, fmt.Errorf(\"parse app config: %w\", err)\n\t}\n\treturn &cfg, nil\n}\n\n// supportedConfigKeys is the single source of truth for the top-level config\n// keys accepted by setConfigValue. The unknown-key error message is generated\n// from this list so the two cannot drift apart when a new key is added.\nvar supportedConfigKeys = []string{\n\t\"provider\",\n\t\"model\",\n\t\"max_tokens\",\n\t\"effort\",\n\t\"providers.<name>.<field>\",\n\t\"custom_providers.<name>.<field>\",\n\t\"mcp_servers.<name>.<field>\",\n\t\"llm.url\",\n\t\"llm.auth_token\",\n\t\"llm.auth_token_cmd\",","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/cmd/opencodereview/config_cmd.go#L394-L430","documentation":"LoadAppConfig reads the OCR app config file from disk and unmarshals it into Config. When the file exists but is not valid JSON (or does not match the Config schema), json.Unmarshal fails and the error is wrapped as \"parse app config: %w\". The underlying encoding/json error names the offset and cause (e.g. syntax error or type mismatch).","triggerScenarios":"Running `ocr config set/get` or any command calling LoadAppConfig on a config file whose content is malformed JSON — trailing commas, comments, single quotes, or a JSON value where a struct field expects a different type (e.g. max_tokens as a string).","commonSituations":"Hand-editing ~/.opencodereview/config.json and introducing a syntax error; pasting YAML instead of JSON; an editor or script writing partial/truncated JSON; merging config changes by hand and corrupting the file.","solutions":["Open the config file at the path shown and fix the JSON syntax error reported by the wrapped encoding/json message (it includes a byte offset)","Validate the file with `cat <path> | python3 -m json.tool` or `jq . <path>` to pinpoint the bad offset","If the file is unrecoverable, delete or rename it — LoadAppConfig returns nil, nil for a missing file and defaults apply","Re-create settings with `ocr config set <key> <value>` instead of manual edits"],"exampleFix":"// before (config.json)\n{ \"provider\": \"bedrock\", \"max_tokens\": \"4096\", }\n// after\n{ \"provider\": \"bedrock\", \"max_tokens\": 4096 }","handlingStrategy":"validation","validationCode":"data, err := os.ReadFile(path)\nif err != nil { return err }\nif !json.Valid(data) {\n    return fmt.Errorf(\"%s is not valid JSON; fix or delete it before running ocr\", path)\n}\ncfg, err := LoadAppConfig(path)","typeGuard":null,"tryCatchPattern":"cfg, err := LoadAppConfig(path)\nif err != nil {\n    var syn *json.SyntaxError\n    if errors.As(err, &syn) {\n        log.Fatalf(\"config JSON invalid at offset %d: %v — fix %s\", syn.Offset, syn, path)\n    }\n    return err\n}","preventionTips":["Validate the config with `jq . ~/.opencodereview/config.json` after every manual edit","Prefer `ocr config set` over hand-editing the file","Keep edits in an editor with JSON schema/lint support","Back up the config before bulk changes"],"tags":["config","json","go"],"backgroundTag":"json-parse-error","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}