{"record":{"id":"11f0b1fa78eaf5b2","repo":"alibaba/open-code-review","slug":"marshal-config-w","errorCode":null,"errorMessage":"marshal config: %w","messagePattern":"marshal config: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/opencodereview/provider_cmd.go","lineNumber":426,"sourceCode":"\t}\n\tcfg.Model = selectedModel\n\n\tif err := saveConfig(configPath, cfg); err != nil {\n\t\treturn err\n\t}\n\n\tfmt.Printf(\"\\nModel set to: %s\\n\", selectedModel)\n\treturn nil\n}\n\nfunc saveConfig(path string, cfg *Config) error {\n\tdir := filepath.Dir(path)\n\tif err := os.MkdirAll(dir, 0o755); err != nil {\n\t\treturn fmt.Errorf(\"create config dir: %w\", err)\n\t}\n\tdata, err := json.MarshalIndent(cfg, \"\", \"    \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marshal config: %w\", err)\n\t}\n\tif err := os.WriteFile(path, data, 0o600); err != nil {\n\t\treturn fmt.Errorf(\"write config: %w\", err)\n\t}\n\tif err := os.Chmod(path, 0o600); err != nil {\n\t\treturn fmt.Errorf(\"chmod config: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc maskKey(key string) string {\n\tif key == \"\" {\n\t\treturn \"(not set)\"\n\t}\n\tif len(key) <= 8 {\n\t\treturn \"***\"\n\t}\n\treturn key[:4] + \"***\" + key[len(key)-4:]","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/cmd/opencodereview/provider_cmd.go#L408-L444","documentation":"saveConfig serializes the Config struct with json.MarshalIndent; if marshaling fails, the error is wrapped as \"marshal config\". For this plain config struct this is rare — it would indicate a value JSON cannot represent (e.g. an unsupported type such as a channel/func field, or NaN via a custom marshaler).","triggerScenarios":"saveConfig invoked (config set/unset commands, provider/model TUI saves) when json.MarshalIndent(cfg) fails — practically only if the Config struct gains a field of an unmarshalable type or a custom MarshalJSON returns an error.","commonSituations":"A newly added config field of unsupported type; corrupted in-memory config built from unusual inputs; a bug in a custom marshaler for a provider entry.","solutions":["Inspect the wrapped inner error to find the offending field/value","Check recently added Config/ProviderEntry fields for unsupported types (chan, func, complex)","Remove or fix the offending value in the config structure","Report/upstream if it is a serialization bug in the tool"],"exampleFix":"// before: field that cannot marshal\ntype Config struct { Hooks chan string `json:\"hooks\"` }\n// after: marshalable representation\ntype Config struct { Hooks []string `json:\"hooks\"` }","handlingStrategy":"try-catch","validationCode":"// pre-flight: ensure the struct round-trips\nif _, err := json.Marshal(cfg); err != nil {\n    return fmt.Errorf(\"config not serializable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := saveConfig(path, cfg); err != nil {\n    var ute *json.UnsupportedTypeError\n    if errors.As(err, &ute) {\n        fmt.Fprintf(os.Stderr, \"field %s cannot be marshaled\\n\", ute.Value)\n    }\n    return err\n}","preventionTips":["Keep Config/ProviderEntry fields limited to JSON-serializable types","Add a round-trip unit test (marshal+unmarshal) whenever adding config fields","Avoid custom MarshalJSON implementations that can return errors"],"tags":["json","serialization","config"],"backgroundTag":"json-marshal-failed","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}