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

  1. Validate the file with `jq . ~/.pi/agent/settings.json` (or any JSON linter) and fix the syntax error it reports.
  2. Remove comments and trailing commas — pi settings.json must be strict RFC 8259 JSON.
  3. Ensure the top level is a JSON object, e.g. {"enabledModels": [...], "defaultModel": "..."}.
  4. 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

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


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/3898328ca80a4674. Report an issue: GitHub.