{"record":{"id":"774af4d5bf370fa5","repo":"chenhg5/cc-connect","slug":"pi-read-settings-w","errorCode":null,"errorMessage":"pi: read settings: %w","messagePattern":"pi: read settings: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/pi/pi.go","lineNumber":433,"sourceCode":"\treturn filepath.Join(dir, \"settings.json\")\n}\n\n// piSettings represents the structure of pi's settings.json relevant fields.\ntype 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))","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/pi/pi.go#L415-L451","documentation":"readSettings successfully resolved the path to pi's settings.json but os.ReadFile failed; the underlying OS error (permission denied, file missing, path is a directory, etc.) is wrapped with %w. This is the adapter's wrapper around any filesystem-level failure while loading pi configuration.","triggerScenarios":"Calling readSettings (via readSettingsModels or readDefaultModel) when ~/.pi/agent/settings.json does not exist (pi never installed/run), is unreadable due to file permissions, or the path is a directory/locked file so os.ReadFile errors.","commonSituations":"Fresh machines where pi CLI has never been launched so settings.json was never created; settings.json owned by another user after running pi with sudo; sync tools (Dropbox) leaving placeholder files; disk/permission issues after user migration.","solutions":["Check the wrapped cause with errors.Is(err, fs.ErrNotExist) — if pi was never run, run `pi` once to generate settings.json or create a minimal one manually.","Fix file permissions: chown/chmod ~/.pi/agent/settings.json so the cc-connect process user can read it.","Verify the file is a regular file, not a directory or broken symlink.","If running as a service, confirm it executes as the same user that owns the pi settings."],"exampleFix":"// before\nmodels, err := readSettingsModels()\nif err != nil {\n    return nil, err\n}\n// after\nmodels, err := readSettingsModels()\nif err != nil {\n    if errors.Is(err, fs.ErrNotExist) {\n        log.Printf(\"pi settings.json missing; using built-in defaults\")\n        return defaultModels, nil\n    }\n    return nil, fmt.Errorf(\"load pi models: %w\", err)\n}","handlingStrategy":"fallback","validationCode":"settingsPath := filepath.Join(homeDir, \".pi\", \"agent\", \"settings.json\")\nif _, err := os.Stat(settingsPath); errors.Is(err, fs.ErrNotExist) {\n    log.Printf(\"pi settings.json missing; run pi once to generate it\")\n}","typeGuard":null,"tryCatchPattern":"models, err := readSettingsModels()\nif err != nil {\n    if errors.Is(err, fs.ErrNotExist) || errors.Is(err, fs.ErrPermission) {\n        return defaultModels, nil // graceful fallback\n    }\n    return nil, err\n}","preventionTips":["Run pi interactively once after install so settings.json exists before daemonized use.","Keep ~/.pi owned by the same user that runs cc-connect; avoid sudo-running pi.","Stat the settings file at service startup and log a clear warning if absent."],"tags":["go","file-io","settings","permissions"],"backgroundTag":"file-read-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"}