sipeed/picoclaw · error
create process hook stderr: %w
Error message
create process hook stderr: %w
What it means
Returned by NewProcessHook when exec.Cmd.StderrPipe() fails while creating the pipe that captures the hook subprocess's stderr. It is the third pipe allocated for the hook; failure means the OS refused the pipe creation, typically fd exhaustion.
Source
Thrown at pkg/agent/hook_process.go:125
return nil, fmt.Errorf("process hook command is required")
}
cmd := exec.Command(opts.Command[0], opts.Command[1:]...)
cmd.Dir = opts.Dir
if len(opts.Env) > 0 {
cmd.Env = append(os.Environ(), opts.Env...)
}
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, fmt.Errorf("create process hook stdin: %w", err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("create process hook stdout: %w", err)
}
stderr, err := cmd.StderrPipe()
if err != nil {
return nil, fmt.Errorf("create process hook stderr: %w", err)
}
// Route hook subprocess startup through the shared isolation entry point so
// process hooks inherit the same isolation behavior as other child processes.
if err := isolation.Start(cmd); err != nil {
return nil, fmt.Errorf("start process hook: %w", err)
}
ph := &ProcessHook{
name: name,
opts: opts,
cmd: cmd,
stdin: stdin,
observeKinds: newProcessHookObserveKinds(opts.ObserveKinds),
pending: make(map[uint64]chan processHookRPCMessage),
done: make(chan struct{}),
}
go ph.readLoop(stdout)View on GitHub (pinned to 49183d7e8d)
Solutions
- Increase the open-file limit for the host process
- Free file descriptors: close idle hooks, connections, or files before mounting another process hook
- Consolidate hooks so fewer subprocess pipes are needed simultaneously
Defensive patterns
Strategy: try-catch
Type guard
func isStderrPipeError(err error) bool {
return err != nil && strings.Contains(err.Error(), "create process hook stderr:")
} Try / catch
ph, err := NewProcessHook(ctx, name, opts)
if err != nil {
if isStderrPipeError(err) {
return fmt.Errorf("cannot allocate hook pipes (fd limit?): %w", err)
}
return err
} Prevention
- Budget ~3 fds per mounted hook plus the subprocess itself
- Clean up dead hooks eagerly to release their pipes
- Set container nofile well above peak hook concurrency
When it happens
Trigger: NewProcessHook gets through stdin and stdout pipe creation but the stderr pipe allocation fails because the fd table is full (EMFILE). The wrapped error is the raw os error.
Common situations: Processes near their fd ceiling — long-running agents with many live hooks, sessions, or connections; restrictive container fd limits.
Related errors
- create process hook stdin: %w
- create process hook stdout: %w
- session not found
- session already completed
- failed to load MCP servers: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/57f81a63b504039b.
Report an issue: GitHub.