wavetermdev/waveterm · error
failed to dup2 stderr: %w
Error message
failed to dup2 stderr: %w
What it means
This error is returned by daemonize when unix.Dup2 fails while redirecting stderr (fd 2) to the log file, after stdout redirection already succeeded. It wraps the underlying syscall errno. Same class of OS-level descriptor problems as the stdout variant.
Source
Thrown at pkg/jobmanager/jobmanager_unix.go:53
logPath := wavebase.GetRemoteJobFilePath(jobId, "log")
logDir := filepath.Dir(logPath)
err = os.MkdirAll(logDir, 0700)
if err != nil {
return fmt.Errorf("failed to create log directory: %w", err)
}
logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
return fmt.Errorf("failed to open log file: %w", err)
}
err = unix.Dup2(int(logFile.Fd()), int(os.Stdout.Fd()))
if err != nil {
return fmt.Errorf("failed to dup2 stdout: %w", err)
}
err = unix.Dup2(int(logFile.Fd()), int(os.Stderr.Fd()))
if err != nil {
return fmt.Errorf("failed to dup2 stderr: %w", err)
}
log.SetOutput(logFile)
log.Printf("job manager daemonized, logging to %s\n", logPath)
log.Printf("job owner clientid: %s\n", clientId)
signal.Ignore(syscall.SIGHUP)
return nil
}
View on GitHub (pinned to a4447c1563)
Solutions
- Ensure fd 2 is open before daemonizing (open /dev/null onto fd 2 if needed).
- Raise the file descriptor limit (ulimit -n / systemd LimitNOFILE).
- Inspect the wrapped errno from the %w error to pinpoint the syscall failure.
Example fix
// before
err = unix.Dup2(int(logFile.Fd()), int(os.Stderr.Fd()))
if err != nil {
return fmt.Errorf("failed to dup2 stderr: %w", err)
}
// after
// guarantee fd 2 is valid before dup2
if _, err := unix.FcntlInt(2, unix.F_GETFD, 0); err != nil {
devnull, _ := os.OpenFile(os.DevNull, os.O_RDWR, 0)
unix.Dup2(int(devnull.Fd()), 2)
}
err = unix.Dup2(int(logFile.Fd()), int(os.Stderr.Fd())) Defensive patterns
Strategy: validation
Validate before calling
if _, err := unix.FcntlInt(2, unix.F_GETFD, 0); err != nil {
devnull, _ := os.OpenFile(os.DevNull, os.O_RDWR, 0)
unix.Dup2(int(devnull.Fd()), 2)
} Try / catch
if err := daemonize(clientId, jobId); err != nil {
if strings.Contains(err.Error(), "dup2 stderr") {
log.Printf("stderr redirect failed: %v", err)
}
return err
} Prevention
- Never launch with `2>&-`; keep stderr open
- Check ulimit -n when opening many files before daemonizing
- Test daemonization under your actual supervisor (systemd, docker)
When it happens
Trigger: daemonize() succeeds opening the log file and redirecting stdout, but unix.Dup2(int(logFile.Fd()), int(os.Stderr.Fd())) returns an error — typically because fd 2 is closed/invalid or fds are exhausted.
Common situations: Process started with stderr closed (e.g. `cmd 2>&-`), supervisor frameworks that close fd 2, or rlimit NOFILE exhaustion.
Related errors
- failed to dup2 stdout: %w
- failed to dup2 stdin: %w
- failed to get pgid: %w
- invalid pgid returned: %d
- failed to daemonize: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/cdbb8b33a6fba202.
Report an issue: GitHub.