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
- Open the file named in the error and fix the JSON syntax (validate with a JSON linter or `jq . file`)
- Remove JSON-incompatible content such as // comments or trailing commas, or migrate the file to crushrc format
- Restore the file from backup or delete it to start with defaults
- 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
- Validate crush.json with a JSON linter or `jq . file` after every hand edit
- Keep configs in version control to diff/restore broken edits
- Prefer the crushrc (Bash) format which tolerates comments over hand-written JSON
- Use editors with JSON schema validation for config files
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- not a valid bedrock api key
- not a valid vercel api key
- mcp stdio config requires a non-empty 'command' field
- mcp http config requires a non-empty 'url' field
- mcp sse config requires a non-empty 'url' field
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/79c13d6600ac76ce.
Report an issue: GitHub.