charmbracelet/crush · error

invalid JSON in config file %s

Error message

invalid JSON in config file %s

What it means

After the base reload, the store merges an optional workspace-level config file (<dataDirectory>/<appName>.json). If that file exists and its bytes are not valid JSON (json.Valid fails), reload aborts with this error rather than silently ignoring the corrupt workspace overrides.

Source

Thrown at internal/config/store.go:1197

	configPaths := lookupConfigs(s.workingDir)
	cfg, loadedPaths, err := loadFromConfigPaths(ctx, configPaths)
	if err != nil {
		return fmt.Errorf("failed to reload config: %w", err)
	}

	// Apply defaults (using existing data directory if set)
	var dataDir string
	if cur := s.Config(); cur != nil && cur.Options != nil {
		dataDir = cur.Options.DataDirectory
	}
	cfg.setDefaults(s.workingDir, dataDir)

	// Merge workspace config if present
	workspacePath := filepath.Join(cfg.Options.DataDirectory, fmt.Sprintf("%s.json", appName))
	if wsData, err := os.ReadFile(workspacePath); err == nil && len(wsData) > 0 {
		if !json.Valid(wsData) {
			return fmt.Errorf("invalid JSON in config file %s", workspacePath)
		}
		merged, mergeErr := loadFromBytes(append([][]byte{mustMarshalConfig(cfg)}, wsData))
		if mergeErr == nil {
			dataDir := cfg.Options.DataDirectory
			*cfg = *merged
			cfg.setDefaults(s.workingDir, dataDir)
			loadedPaths = append(loadedPaths, workspacePath)
		}
	}

	// Validate hooks after all config merging is complete so matcher
	// regexes are recompiled on the reloaded config (mirrors Load).
	if err := cfg.ValidateHooks(); err != nil {
		return fmt.Errorf("invalid hook configuration on reload: %w", err)
	}

	// Save current state for potential rollback BEFORE configureProviders,
	// which may write to disk via RemoveConfigField (e.g. removing stale

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Run the file through a JSON linter (jq . <dataDir>/crush.json) and fix the syntax error.
  2. Remove or rename the corrupt workspace file if the overrides are not needed; reload will succeed without it.
  3. Re-save the file ensuring a complete write (check disk space / editor behavior).

Example fix

// before: JSONC/trailing comma in workspace config
{"permissions": {"bash": ["git *"],}}
// after
{"permissions": {"bash": ["git *"]}}
Defensive patterns

Strategy: validation

Validate before calling

wsPath := filepath.Join(dataDir, "crush.json")
if b, err := os.ReadFile(wsPath); err == nil && len(b) > 0 && !json.Valid(b) { fixOrRemove(wsPath) }

Try / catch

if err := reload(); err != nil && strings.Contains(err.Error(), "invalid JSON") {
    os.Remove(workspaceConfigPath); reload()
}

Prevention

When it happens

Trigger: os.ReadFile succeeds on <DataDirectory>/<appName>.json with non-empty content and json.Valid(wsData) returns false — e.g. trailing commas, comments, truncated write, or a non-JSON file placed at that path.

Common situations: A crashed previous run left a partially written workspace config; a user pasted YAML or JSONC into the .json file; editor auto-save wrote a truncated file.

Understand the failure class

Related errors


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