{"record":{"id":"3898328ca80a4674","repo":"chenhg5/cc-connect","slug":"pi-parse-settings-w","errorCode":null,"errorMessage":"pi: parse settings: %w","messagePattern":"pi: parse settings: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/pi/pi.go","lineNumber":437,"sourceCode":"type piSettings struct {\n\tEnabledModels  []string `json:\"enabledModels\"`\n\tDefaultModel   string   `json:\"defaultModel\"`\n\tDefaultProvider string  `json:\"defaultProvider\"`\n}\n\n// readSettings reads and parses pi's settings.json.\nfunc readSettings() (*piSettings, error) {\n\tpath := settingsPath()\n\tif path == \"\" {\n\t\treturn nil, fmt.Errorf(\"pi: cannot determine settings path\")\n\t}\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"pi: read settings: %w\", err)\n\t}\n\tvar s piSettings\n\tif err := json.Unmarshal(data, &s); err != nil {\n\t\treturn nil, fmt.Errorf(\"pi: parse settings: %w\", err)\n\t}\n\treturn &s, nil\n}\n\n// readSettingsModels returns the enabledModels from settings.json as ModelOptions.\nfunc readSettingsModels() ([]core.ModelOption, error) {\n\ts, err := readSettings()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(s.EnabledModels) == 0 {\n\t\treturn nil, nil\n\t}\n\tmodels := make([]core.ModelOption, 0, len(s.EnabledModels))\n\tfor _, m := range s.EnabledModels {\n\t\toption := core.ModelOption{Name: m}\n\t\t// Derive a short alias from the last segment after the final \"/\".\n\t\tif idx := strings.LastIndex(m, \"/\"); idx >= 0 && idx+1 < len(m) {","sourceCodeStart":419,"sourceCodeEnd":455,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/pi/pi.go#L419-L455","documentation":"readSettings read pi's settings.json from disk but json.Unmarshal failed to parse it into the piSettings struct (enabledModels, defaultModel, defaultProvider fields). The underlying JSON error is wrapped with %w. This indicates the settings file is present but syntactically or structurally invalid.","triggerScenarios":"Calling readSettings (via readSettingsModels or readDefaultModel) when settings.json contains malformed JSON (trailing commas, comments, truncated writes) or a top-level non-object JSON value (e.g. an array, string, or null).","commonSituations":"Users hand-editing settings.json and leaving syntax errors; concurrent pi process writing the file while the adapter reads it (torn read); editors saving JSONC (with comments) that strict json.Unmarshal rejects; file corruption after crashes or interrupted sync.","solutions":["Validate the file with `jq . ~/.pi/agent/settings.json` (or any JSON linter) and fix the syntax error it reports.","Remove comments and trailing commas — pi settings.json must be strict RFC 8259 JSON.","Ensure the top level is a JSON object, e.g. {\"enabledModels\": [...], \"defaultModel\": \"...\"}.","Re-generate the file by running pi once if it is corrupted beyond easy repair."],"exampleFix":"// before (settings.json, invalid)\n{\n  \"defaultModel\": \"claude-sonnet-4\", // my favorite\n}\n// after (settings.json, valid)\n{\n  \"defaultModel\": \"claude-sonnet-4\"\n}","handlingStrategy":"validation","validationCode":"data, err := os.ReadFile(filepath.Join(homeDir, \".pi\", \"agent\", \"settings.json\"))\nif err == nil {\n    var probe map[string]any\n    if jerr := json.Unmarshal(data, &probe); jerr != nil {\n        log.Printf(\"pi settings.json invalid JSON: %v\", jerr)\n    }\n}","typeGuard":null,"tryCatchPattern":"s, err := readSettings()\nif err != nil {\n    var jsonErr *json.SyntaxError\n    if errors.As(err, &jsonErr) {\n        return fmt.Errorf(\"pi settings.json malformed at offset %d: %w (fix with a JSON linter)\", jsonErr.Offset, err)\n    }\n    return nil, err\n}","preventionTips":["Validate settings.json with `jq .` after every hand edit.","Keep the file plain JSON — no comments or trailing commas (no JSONC).","Avoid editing the file while pi is running to prevent torn writes."],"tags":["go","json","settings","parse-error"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}