charmbracelet/crush · error
shell config %s produced invalid JSON
Error message
shell config %s produced invalid JSON
What it means
After shellconfig.LoadShellConfig succeeds it must yield valid JSON. If the produced byte slice is non-empty but json.Valid reports invalid, loadFromConfigPaths aborts with this error. This guards against a crushrc that evaluates without error but emits malformed JSON.
Source
Thrown at internal/config/load.go:1000
if err != nil {
if os.IsNotExist(err) {
continue
}
return nil, nil, fmt.Errorf("failed to open config file %s: %w", path, err)
}
if len(data) == 0 {
continue
}
dir := filepath.Dir(path)
if isShellConfig(path) {
jsonBytes, err := shellconfig.LoadShellConfig(ctx, path, data)
if err != nil {
return nil, nil, fmt.Errorf("failed to load shell config %s: %w", path, err)
}
if len(jsonBytes) > 0 {
if !json.Valid(jsonBytes) {
return nil, nil, fmt.Errorf("shell config %s produced invalid JSON", path)
}
addTopLevelKeys(shDirKeys, dir, jsonBytes)
configs = append(configs, jsonBytes)
loaded = append(loaded, path)
}
} else {
if !json.Valid(data) {
return nil, nil, fmt.Errorf("invalid JSON in config file %s", path)
}
addTopLevelKeys(jsonDirKeys, dir, data)
configs = append(configs, data)
loaded = append(loaded, path)
}
}
// Warn if both a JSON config and a crushrc exist in the same directory
// and define overlapping top-level keys. Disjoint coexistence is
// intentional and not worth warning about.View on GitHub (pinned to 7944b8e522)
Solutions
- Validate the JSON your crushrc should produce by inspecting the inner generated output or running the builtins manually
- Remove or fix the builtin/option emitting the malformed output
- Check for BOM or non-UTF8 characters in the crushrc and re-save as UTF-8
- Update Crush — builtin emission bugs are fixed in newer releases
Example fix
# before: duplicate provider blocks emit conflicting JSON keys
provider a { ... }
provider a { ... }
# after: declare each provider once
provider a { ... } Defensive patterns
Strategy: validation
Validate before calling
// after producing JSON from a custom builtin pipeline:
if !json.Valid(jsonBytes) {
return fmt.Errorf("shell config produced invalid JSON")
} Try / catch
if err := config.Load(ctx, ...); err != nil {
if strings.Contains(err.Error(), "produced invalid JSON") {
// disable custom builtins and bisect which one emits bad output
}
} Prevention
- Save config files as UTF-8 without BOM
- Test custom builtins' emitted JSON with jq
- Keep Crush updated for builtin emission fixes
When it happens
Trigger: Load processes a crushrc where LoadShellConfig returns bytes that are non-empty and fail json.Valid — e.g. duplicated keys from bad merging, truncated output, or a builtin emitting non-JSON text into the config.
Common situations: Custom or outdated shell builtins writing raw text; encoding issues (BOM, non-UTF8 bytes) in generated JSON; a bug in a custom builtin that produces near-JSON output.
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
- failed to load projects: %w
- invalid JSON in config file %s
- failed to load shell config %s: %w
- task agent not configured
- small model provider not configured
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/4992bf1f10cb6fe3.
Report an issue: GitHub.