chenhg5/cc-connect · error
pi: parse settings: %w
Error message
pi: parse settings: %w
What it means
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.
Source
Thrown at agent/pi/pi.go:437
type piSettings struct {
EnabledModels []string `json:"enabledModels"`
DefaultModel string `json:"defaultModel"`
DefaultProvider string `json:"defaultProvider"`
}
// readSettings reads and parses pi's settings.json.
func readSettings() (*piSettings, error) {
path := settingsPath()
if path == "" {
return nil, fmt.Errorf("pi: cannot determine settings path")
}
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("pi: read settings: %w", err)
}
var s piSettings
if err := json.Unmarshal(data, &s); err != nil {
return nil, fmt.Errorf("pi: parse settings: %w", err)
}
return &s, nil
}
// readSettingsModels returns the enabledModels from settings.json as ModelOptions.
func readSettingsModels() ([]core.ModelOption, error) {
s, err := readSettings()
if err != nil {
return nil, err
}
if len(s.EnabledModels) == 0 {
return nil, nil
}
models := make([]core.ModelOption, 0, len(s.EnabledModels))
for _, m := range s.EnabledModels {
option := core.ModelOption{Name: m}
// Derive a short alias from the last segment after the final "/".
if idx := strings.LastIndex(m, "/"); idx >= 0 && idx+1 < len(m) {View on GitHub (pinned to 4000b2338a)
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.
Example fix
// before (settings.json, invalid)
{
"defaultModel": "claude-sonnet-4", // my favorite
}
// after (settings.json, valid)
{
"defaultModel": "claude-sonnet-4"
} Defensive patterns
Strategy: validation
Validate before calling
data, err := os.ReadFile(filepath.Join(homeDir, ".pi", "agent", "settings.json"))
if err == nil {
var probe map[string]any
if jerr := json.Unmarshal(data, &probe); jerr != nil {
log.Printf("pi settings.json invalid JSON: %v", jerr)
}
} Try / catch
s, err := readSettings()
if err != nil {
var jsonErr *json.SyntaxError
if errors.As(err, &jsonErr) {
return fmt.Errorf("pi settings.json malformed at offset %d: %w (fix with a JSON linter)", jsonErr.Offset, err)
}
return nil, err
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- parse existing Agy hooks %s: %w
- marshal Agy permission hook: %w
- marshal Agy hooks overlay: %w
- marshal: %w
- parse auth.json: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/3898328ca80a4674.
Report an issue: GitHub.