wavetermdev/waveterm · error
cannot create ready pipe: %w
Error message
cannot create ready pipe: %w
What it means
os.Pipe() failed while creating the readiness-notification pipe pair used by the job manager child process to signal 'Wave-JobManagerStart'. This is a kernel-level fd allocation failure (EMFILE/ENFILE typically), surfaced wrapped with %w.
Source
Thrown at pkg/wshrpc/wshremote/wshremote_job.go:147
defer impl.Lock.Unlock()
return impl.JobManagerMap[jobId]
}
func (impl *ServerImpl) RemoteStartJobCommand(ctx context.Context, data wshrpc.CommandRemoteStartJobData) (*wshrpc.CommandStartJobRtnData, error) {
log.Printf("RemoteStartJobCommand: starting, jobid=%s, clientid=%s\n", data.JobId, data.ClientId)
if impl.Router == nil {
return nil, fmt.Errorf("cannot start remote job: no router available")
}
wshPath, err := impl.getWshPath()
if err != nil {
return nil, err
}
log.Printf("RemoteStartJobCommand: wshPath=%s\n", wshPath)
readyPipeRead, readyPipeWrite, err := os.Pipe()
if err != nil {
return nil, fmt.Errorf("cannot create ready pipe: %w", err)
}
defer readyPipeRead.Close()
defer readyPipeWrite.Close()
cmd := exec.Command(wshPath, "jobmanager", "--jobid", data.JobId, "--clientid", data.ClientId)
if data.PublicKeyBase64 != "" {
cmd.Env = append(os.Environ(), "WAVETERM_PUBLICKEY="+data.PublicKeyBase64)
}
cmd.ExtraFiles = []*os.File{readyPipeWrite}
stdin, err := cmd.StdinPipe()
if err != nil {
return nil, fmt.Errorf("cannot create stdin pipe: %w", err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("cannot create stdout pipe: %w", err)
}
stderr, err := cmd.StderrPipe()View on GitHub (pinned to a4447c1563)
Solutions
- Check fd usage (lsof / /proc/<pid>/fd) and fix descriptor leaks
- Raise the soft/hard file descriptor limit (ulimit -n) or the container's nofile limit
- Restart the process to clear leaked descriptors
Example fix
// before $ ulimit -n 1024 // after $ ulimit -n 65536 # or set LimitNOFILE=65536 in the systemd unit / nofile in container runtime
Defensive patterns
Strategy: try-catch
Validate before calling
var lim syscall.Rlimit
syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim)
if lim.Cur < 1024 {
lim.Cur = 65536
syscall.Setrlimit(syscall.RLIMIT_NOFILE, &lim)
} Try / catch
rtn, err := server.RemoteStartJobCommand(ctx, data)
if err != nil {
var pe *os.PathError
if errors.As(err, &pe) {
// pipe allocation failure: check fd limits before retrying
}
return err
} Prevention
- Monitor open fd counts on the server process
- Close all pipes/streams after each job completes
- Set generous RLIMIT_NOFILE in the service unit or container
When it happens
Trigger: Calling RemoteStartJobCommand when the process has exhausted its file descriptor limit or the OS cannot allocate pipes (fd table full, low memory).
Common situations: Long-running servers leaking file descriptors until hitting ulimit -n; systems with very low RLIMIT_NOFILE; containerized environments with small fd caps.
Related errors
- cannot create stdin pipe: %w
- cannot create stdout pipe: %w
- cannot create stderr pipe: %w
- failed to create stdout pipe: %w
- error reading ready pipe: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/4d6ab22a3025aabf.
Report an issue: GitHub.