charmbracelet/crush · error
invalid hook configuration on reload: %w
Error message
invalid hook configuration on reload: %w
What it means
On reload, hooks defined in the reloaded config must be re-validated (matcher regexes recompiled) via cfg.ValidateHooks, mirroring initial Load. If validation fails, reload aborts with this wrapped error and the store rolls back, keeping the previously working hooks.
Source
Thrown at internal/config/store.go:1211
// 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
// OAuth providers). Capturing after would snapshot a config that has
// already been mutated, and the rollback would restore corrupted state.
oldConfig := s.Config()
oldLoadedPaths := s.loadedPaths
oldResolver := s.resolver
oldKnownProviders := s.knownProviders
oldOverrides := s.overrides
oldWorkspacePath := s.workspacePath
// Preserve runtime overrides
overrides := s.overrides
// Reapply model choices made in this instance. The global config file is
// shared, so it may now name a model a sibling instance selected; aView on GitHub (pinned to 7944b8e522)
Solutions
- Fix the hook definition flagged by the wrapped error — usually an invalid matcher regex or missing command field.
- Test the regex in isolation (go playground or regex101 with RE2 syntax) before adding it to config.
- Roll back the recent hook edit and reload to restore the working state.
- Validate hooks locally via the config validation path before sharing the config.
Example fix
// before: invalid regex hook pretooluse --matcher "(edit|write" --command ./check.sh // after hook pretooluse --matcher "(edit|write)" --command ./check.sh
Defensive patterns
Strategy: validation
Validate before calling
for _, h := range cfg.Hooks { if _, err := regexp.Compile(h.Matcher); err != nil { return err }; if h.Command == "" { return errors.New("empty hook command") } } Try / catch
if err := reload(); err != nil && strings.Contains(err.Error(), "invalid hook configuration") {
revertLastHookEdit(); reload()
} Prevention
- Test hook matcher regexes (RE2) before committing config
- Keep hook commands non-empty and executable
- Validate hooks in CI with the same config schema
When it happens
Trigger: cfg.ValidateHooks() returns an error after merging: a hook with an invalid matcher regex, empty/missing command, or unsupported event name in the newly loaded crushrc/crush.json.
Common situations: User added a hook in the session directory with a bad regex like "(" or a typo'd event; a shared team config was updated with an incompatible hook schema version.
Related errors
- invalid hook configuration: %w
- hook %s[%d]: invalid matcher regex %q: %w
- invalid regex pattern: %w
- hook %s[%d]: command is required
- prompt is required
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/5a0de138306d390b.
Report an issue: GitHub.