sipeed/picoclaw · error
no hook modes enabled
Error message
no hook modes enabled
What it means
Thrown by processHookOptionsFromConfig when a process hook is configured but ends up with zero modes enabled: no observe entries produced a mode and no intercept entries matched. The library refuses to mount a hook that would receive no events at all, since it could never do anything.
Source
Thrown at pkg/agent/hook_mount.go:263
opts.ObserveKinds = observeKinds
for _, intercept := range spec.Intercept {
switch intercept {
case "before_llm", "after_llm":
opts.InterceptLLM = true
case "before_tool", "after_tool":
opts.InterceptTool = true
case "approve_tool":
opts.ApproveTool = true
case "":
continue
default:
return ProcessHookOptions{}, fmt.Errorf("unsupported intercept %q", intercept)
}
}
if !opts.Observe && !opts.InterceptLLM && !opts.InterceptTool && !opts.ApproveTool {
return ProcessHookOptions{}, fmt.Errorf("no hook modes enabled")
}
return opts, nil
}
func processHookEnvFromMap(envMap map[string]string) []string {
if len(envMap) == 0 {
return nil
}
keys := make([]string, 0, len(envMap))
for key := range envMap {
keys = append(keys, key)
}
sort.Strings(keys)
env := make([]string, 0, len(keys))
for _, key := range keys {View on GitHub (pinned to 49183d7e8d)
Solutions
- Add at least one mode to the hook: an observe list (e.g. observe: ["*"]) or an intercept entry (e.g. intercept: ["before_tool"])
- If the hook is not meant to run, remove the entry or set enabled: false instead of leaving a mode-less enabled hook
Example fix
# before
hooks:
process:
my-hook:
enabled: true
command: ["./hook"]
# after
hooks:
process:
my-hook:
enabled: true
command: ["./hook"]
observe: ["*"]
intercept: ["before_tool"] Defensive patterns
Strategy: validation
Validate before calling
func hookHasMode(spec config.ProcessHookConfig) bool {
if len(spec.Observe) > 0 {
return true // note: observe: [""] alone does NOT enable a mode
}
for _, v := range spec.Intercept {
if v != "" {
return true
}
}
return false
}
if spec.Enabled && !hookHasMode(spec) {
return fmt.Errorf("hook %s enabled without observe or intercept", name)
} Try / catch
opts, err := processHookOptionsFromConfig(spec)
if err != nil {
return fmt.Errorf("hook %q misconfigured: %w", name, err)
} Prevention
- Never enable a process hook without declaring observe or intercept
- Treat observe: [""] as disabled — only non-empty kinds or "*" enable observing
- Add a startup config assertion that every enabled hook has at least one mode
When it happens
Trigger: A hook config with `enabled: true` (and a command) that declares neither `observe` nor `intercept`, or declares only empty strings — e.g. observe: [""] or intercept: [""], both of which are skipped. Note that observe: [] is falsy for the Observe flag.
Common situations: Minimal copy-pasted hook config that only sets command; a config where observe/intercept keys exist but are commented out; refactoring that accidentally drops the mode lists.
Related errors
- build builtin hook %q: %w
- configure process hook %q: %w
- command is required
- unsupported intercept %q
- unsupported observe event %q
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/3ec1b156c15a5181.
Report an issue: GitHub.