charmbracelet/crush · error
invalid hook configuration: %w
Error message
invalid hook configuration: %w
What it means
After all config merging completes, Load() calls cfg.ValidateHooks() to compile hook matcher regexes and check hook definitions. Any hook-validation failure is wrapped with this message so the user knows the problem is in the hooks section of their config.
Source
Thrown at internal/config/load.go:85
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)
}
if !isInsideWorktree() {
const depth = 2
const items = 100
slog.Warn("No git repository detected in working directory, will limit file walk operations", "depth", depth, "items", items)
assignIfNil(&cfg.Tools.Ls.MaxDepth, depth)
assignIfNil(&cfg.Tools.Ls.MaxItems, items)
assignIfNil(&cfg.Options.TUI.Completions.MaxDepth, depth)
assignIfNil(&cfg.Options.TUI.Completions.MaxItems, items)
}
if isAppleTerminal() {
slog.Warn("Detected Apple Terminal, enabling transparent mode")
assignIfNil(&cfg.Options.TUI.Transparent, true)
}
// Load known providers, this loads the config from catwalk. A failedView on GitHub (pinned to 7944b8e522)
Solutions
- Read the wrapped %w error to identify which hook failed and fix its definition
- Check that every hook's matcher is a valid regular expression
- Verify hook event names match supported events (see HOOKS.md)
- Temporarily remove hooks from workspace config to isolate whether the global or workspace hook is at fault
Example fix
// before (crush.json)
"hooks": {"pre_tool_use": [{"matcher": "edit(", "command": "lint.sh"}]}
// after
"hooks": {"pre_tool_use": [{"matcher": "edit", "command": "lint.sh"}]} Defensive patterns
Strategy: validation
Validate before calling
cfg, err := loadRawConfig()
if err != nil { return err }
if err := cfg.ValidateHooks(); err != nil {
return fmt.Errorf("hooks invalid before startup: %w", err)
} Try / catch
store, err := config.Load(ctx, opts)
if err != nil {
if strings.HasPrefix(err.Error(), "invalid hook configuration:") {
log.Fatalf("Fix hooks in crush config: %v", err)
}
return err
} Prevention
- Test hook matcher regexes with a regex tester before adding them to config
- Keep hook event names against the documented list in HOOKS.md
- Add hooks incrementally, running crush after each change
- Keep global and workspace hooks separate to isolate failures
When it happens
Trigger: Load() finishes merging global and workspace configs; ValidateHooks() returns an error such as an invalid matcher regex or malformed hook command/event definition defined in crushrc/crush.json.
Common situations: Typo in a hook event name; a preToolUse matcher regex that doesn't compile (e.g. unbalanced parenthesis '['); hook defined in workspace config overriding/breaking a valid global hook.
Related errors
- hook %s[%d]: invalid matcher regex %q: %w
- hook %s[%d]: command is required
- invalid hook configuration on reload: %w
- not a valid bedrock api key
- not a valid vercel api key
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/bf22cbbb82f270fa.
Report an issue: GitHub.