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 staleView on GitHub (pinned to 7944b8e522)
Solutions
- Run the file through a JSON linter (jq . <dataDir>/crush.json) and fix the syntax error.
- Remove or rename the corrupt workspace file if the overrides are not needed; reload will succeed without it.
- 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
- Never paste JSONC/YAML into .json files
- Ensure atomic writes (write temp + rename) for generated configs
- Validate with jq before saving
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- requested channels differ from the existing workspace; chann
- failed to reload config: %w
- client not attached
- workspace closing
- not found
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/a42691763e3bd367.
Report an issue: GitHub.