sipeed/picoclaw · error
start process hook %q: %w
Error message
start process hook %q: %w
What it means
After config validation, NewProcessHook spawns the hook's command and speaks stdio to it. This wrapper means process startup failed — the binary could not be executed or the process died during startup/handshake. The hook name plus the wrapped exec error identify the culprit; the partially started hook is not mounted.
Source
Thrown at pkg/agent/hook_mount.go:175
Source: HookSourceInProcess,
Hook: hook,
}); err != nil {
return fmt.Errorf("mount builtin hook %q: %w", name, err)
}
mounted = append(mounted, name)
}
processNames := enabledProcessHookNames(al.cfg.Hooks.Processes)
for _, name := range processNames {
spec := al.cfg.Hooks.Processes[name]
opts, buildErr := processHookOptionsFromConfig(spec)
if buildErr != nil {
return fmt.Errorf("configure process hook %q: %w", name, buildErr)
}
processHook, buildErr := NewProcessHook(ctx, name, opts)
if buildErr != nil {
return fmt.Errorf("start process hook %q: %w", name, buildErr)
}
if err := al.MountHook(HookRegistration{
Name: name,
Priority: spec.Priority,
Source: HookSourceProcess,
Hook: processHook,
}); err != nil {
_ = processHook.Close()
return fmt.Errorf("mount process hook %q: %w", name, err)
}
mounted = append(mounted, name)
}
return nil
}
func enabledBuiltinHookNames(specs map[string]config.BuiltinHookConfig) []string {
if len(specs) == 0 {View on GitHub (pinned to 49183d7e8d)
Solutions
- Run the exact command array from config in the same environment (same user, PATH, dir) to reproduce
- Use an absolute path for command[0] instead of relying on PATH
- chmod +x the script and ensure a shebang (or invoke the interpreter explicitly: ["python", "/opt/hook.py"])
- Verify spec.dir exists and add required env entries under the hook's env map
- Check the hook's own stderr/startup logs — an immediately exiting process surfaces here
Example fix
// before "command": ["audit-hook"] // after "command": ["/usr/local/bin/audit-hook"] // or for scripts: "command": ["python3", "/opt/picoclaw/hooks/audit_hook.py"]
Defensive patterns
Strategy: validation
Validate before calling
for name, p := range cfg.Hooks.Processes {
if !p.Enabled || len(p.Command) == 0 {
continue
}
if filepath.IsAbs(p.Command[0]) {
if _, err := os.Stat(p.Command[0]); err != nil {
return fmt.Errorf("hooks.processes.%s: binary missing: %w", name, err)
}
} else if _, err := exec.LookPath(p.Command[0]); err != nil {
return fmt.Errorf("hooks.processes.%s: %s not in PATH: %w", name, p.Command[0], err)
}
if p.Dir != "" {
if _, err := os.Stat(p.Dir); err != nil {
return fmt.Errorf("hooks.processes.%s: dir missing: %w", name, err)
}
}
} Prevention
- Use absolute paths for hook binaries — service managers and containers have different PATH
- Add the hook's runtime (python/node) to the image and verify with exec.LookPath in CI
- Log hook stderr to a file so immediately-exiting processes are diagnosable
When it happens
Trigger: hooks.processes.<name>.enabled=true with a command whose binary does not exist in PATH, is not executable, targets the wrong architecture, runs from a nonexistent dir, or exits immediately (missing interpreter like python/node, missing env).
Common situations: PATH differences under systemd/docker (works in shell, fails as a service); script without a shebang or without +x; relative dir that only exists in another cwd; missing env var the hook needs at boot.
Related errors
- configure process hook %q: %w
- mount process hook %q: %w
- unsupported transport %q
- command is required
- builtin hook %q is not registered
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/2d3c53d6f6a320b1.
Report an issue: GitHub.