sipeed/picoclaw · error

unsupported intercept %q

Error message

unsupported intercept %q

What it means

Thrown by processHookOptionsFromConfig (pkg/agent/hook_mount.go) while validating a process hook's `intercept` list from config.ProcessHookConfig. Every entry must be exactly one of the supported intercept names: before_llm, after_llm, before_tool, after_tool, approve_tool. Empty strings are skipped; anything else is rejected with the offending value echoed back.

Source

Thrown at pkg/agent/hook_mount.go:258

	observeKinds, observeEnabled, err := processHookObserveKindsFromConfig(spec.Observe)
	if err != nil {
		return ProcessHookOptions{}, err
	}
	opts.Observe = observeEnabled
	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)

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Change the offending intercept value to one of: before_llm, after_llm, before_tool, after_tool, approve_tool (exact lowercase, underscores)
  2. Check for casing mistakes — the match is case-sensitive, so "Before_LLM" fails
  3. Remove the stale entry if it was valid in an older version and the hook no longer needs it

Example fix

# before (hooks config)
hooks:
  process:
    my-hook:
      enabled: true
      command: ["./hook"]
      intercept: ["Before_LLM", "pre_tool"]

# after
hooks:
  process:
    my-hook:
      enabled: true
      command: ["./hook"]
      intercept: ["before_llm", "before_tool"]
Defensive patterns

Strategy: validation

Validate before calling

var supportedIntercepts = map[string]bool{
    "before_llm": true, "after_llm": true,
    "before_tool": true, "after_tool": true,
    "approve_tool": true,
}

func validateIntercepts(spec config.ProcessHookConfig) error {
    for _, v := range spec.Intercept {
        if v == "" {
            continue
        }
        if !supportedIntercepts[v] {
            return fmt.Errorf("intercept %q unsupported; want one of before_llm, after_llm, before_tool, after_tool, approve_tool", v)
        }
    }
    return nil
}

Try / catch

opts, err := processHookOptionsFromConfig(spec)
if err != nil {
    // config error: fail fast at startup with the offending value in the message
    log.Fatalf("invalid hook config: %v", err)
}

Prevention

When it happens

Trigger: A process hook config entry whose intercept array contains a value like "pre_llm", "Before_Tool", "on_tool", or "tool_approve" — i.e. any string that is not byte-for-byte one of the five supported names. The error fires at hook-mount time, before any process is spawned.

Common situations: Typos or wrong casing in YAML/JSON hook config; copying event names from a different hook system (e.g. Claude Code hook names) into this config; a renamed intercept name after upgrading the library.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/7f7d1c931bcb0390. Report an issue: GitHub.