charmbracelet/crush · error

invalid JSON in config file %s

Error message

invalid JSON in config file %s

What it means

Load() validates that the workspace config file (highest-priority crush.json) contains syntactically valid JSON before merging it. It fails fast with the file path so the user knows which file to fix, because a partial merge of malformed JSON would silently produce a broken config.

Source

Thrown at internal/config/load.go:69

	cfg.setDefaults(workingDir, dataDir)

	store := &ConfigStore{
		config:         cfg,
		workingDir:     workingDir,
		globalDataPath: GlobalConfigData(),
		workspacePath:  filepath.Join(cfg.Options.DataDirectory, fmt.Sprintf("%s.json", appName)),
		loadedPaths:    loadedPaths,
	}

	if debug {
		cfg.Options.Debug = true
	}

	// Load workspace config last so it has highest priority.
	if wsData, err := os.ReadFile(store.workspacePath); err == nil && len(wsData) > 0 {
		if !json.Valid(wsData) {
			return nil, fmt.Errorf("invalid JSON in config file %s", store.workspacePath)
		}
		merged, mergeErr := loadFromBytes(append([][]byte{mustMarshalConfig(cfg)}, wsData))
		if mergeErr == nil {
			// Preserve defaults that setDefaults already applied.
			dataDir := cfg.Options.DataDirectory
			*cfg = *merged
			cfg.setDefaults(workingDir, dataDir)
			store.config = cfg
			store.loadedPaths = append(store.loadedPaths, store.workspacePath)
		}
	}

	// Validate hooks after all config merging is complete so workspace
	// hooks also get their matcher regexes compiled.
	if err := cfg.ValidateHooks(); err != nil {
		return nil, fmt.Errorf("invalid hook configuration: %w", err)
	}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Open the file named in the error and fix the JSON syntax (validate with a JSON linter or `jq . file`)
  2. Remove JSON-incompatible content such as // comments or trailing commas, or migrate the file to crushrc format
  3. Restore the file from backup or delete it to start with defaults
  4. Check for a crashed editor or interrupted write that truncated the file

Example fix

// before (crush.json)
{"providers": {"anthropic": {"api_key": "sk-...",}},}
// after
{"providers": {"anthropic": {"api_key": "sk-..."}}}
Defensive patterns

Strategy: validation

Validate before calling

data, err := os.ReadFile(configPath)
if err != nil { return err }
if !json.Valid(data) {
    return fmt.Errorf("fix JSON syntax in %s: run `jq . %s` to locate the error", configPath, configPath)
}

Try / catch

store, err := config.Load(ctx, opts)
if err != nil {
    var pathErr *os.PathError
    if strings.Contains(err.Error(), "invalid JSON in config file") {
        // surface the file path from err and prompt user to repair
    }
    return err
}

Prevention

When it happens

Trigger: os.ReadFile on store.workspacePath succeeds and returns bytes, but json.Valid(wsData) returns false — e.g. trailing commas, comments in JSON, truncated writes, or hand-edits that broke syntax.

Common situations: Users hand-editing ~/.config/crush/crush.json and leaving a syntax error; editors saving partial content; tools appending to the JSON producing invalid output; copy-pasted config containing comments or trailing commas.

Understand the failure class

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/79c13d6600ac76ce. Report an issue: GitHub.