{"record":{"id":"77350840d807cd84","repo":"wavetermdev/waveterm","slug":"failed-to-dup2-stdin-w","errorCode":null,"errorMessage":"failed to dup2 stdin: %w","messagePattern":"failed to dup2 stdin: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/jobmanager/jobmanager_unix.go","lineNumber":32,"sourceCode":"\t\"syscall\"\n\n\t\"github.com/wavetermdev/waveterm/pkg/wavebase\"\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc daemonize(clientId string, jobId string) error {\n\t_, err := unix.Setsid()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to setsid: %w\", err)\n\t}\n\n\tdevNull, err := os.OpenFile(\"/dev/null\", os.O_RDWR, 0)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to open /dev/null: %w\", err)\n\t}\n\terr = unix.Dup2(int(devNull.Fd()), int(os.Stdin.Fd()))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to dup2 stdin: %w\", err)\n\t}\n\tdevNull.Close()\n\n\tlogPath := wavebase.GetRemoteJobFilePath(jobId, \"log\")\n\tlogDir := filepath.Dir(logPath)\n\terr = os.MkdirAll(logDir, 0700)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create log directory: %w\", err)\n\t}\n\n\tlogFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to open log file: %w\", err)\n\t}\n\terr = unix.Dup2(int(logFile.Fd()), int(os.Stdout.Fd()))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to dup2 stdout: %w\", err)\n\t}","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/jobmanager/jobmanager_unix.go#L14-L50","documentation":"daemonize redirects stdin to /dev/null via unix.Dup2(int(devNull.Fd()), int(os.Stdin.Fd())). This error wraps the Dup2 errno. Dup2 over stdin almost never fails in normal conditions; failures indicate an invalid file descriptor or hitting the file-descriptor limit during exotic startup states.","triggerScenarios":"unix.Dup2 fails with EBADF when os.Stdin's fd (0) is closed/invalid at daemonize time, or with EMFILE/other errno under fd-table corruption; also triggered when stdin was already closed by prior startup code before daemonize runs.","commonSituations":"Parent process closed fd 0 before exec'ing the job; stdin shutdown race during daemonization; resource limits or seccomp filters blocking dup2 in hardened environments.","solutions":["Ensure fd 0 (stdin) is open before calling daemonize; do not close std fds in startup code","If stdin may be closed, reopen /dev/null onto fd 0 first, then run daemonize","Inspect the wrapped errno: EBADF means invalid fd — check exec/fork handling; EPERM may indicate seccomp restrictions"],"exampleFix":"// before\nerr = unix.Dup2(int(devNull.Fd()), int(os.Stdin.Fd()))\nif err != nil {\n    return fmt.Errorf(\"failed to dup2 stdin: %w\", err)\n}\n// after\nif err := ensureFdOpen(0, os.O_RDWR); err != nil { // reopen /dev/null onto fd 0 if closed\n    return err\n}\nif err := unix.Dup2(int(devNull.Fd()), int(os.Stdin.Fd())); err != nil {\n    return fmt.Errorf(\"failed to dup2 stdin: %w\", err)\n}","handlingStrategy":"validation","validationCode":"// ensure fd 0 is open before daemonize\nif _, err := unix.FcntlInt(0, unix.F_GETFD, 0); err != nil {\n    // reopen /dev/null onto fd 0\n    f, _ := os.OpenFile(\"/dev/null\", os.O_RDWR, 0)\n    unix.Dup2(int(f.Fd()), 0)\n}","typeGuard":null,"tryCatchPattern":"if err := daemonize(clientId, jobId); err != nil {\n    if strings.Contains(err.Error(), \"failed to dup2 stdin\") {\n        log.Printf(\"stdin fd invalid at daemonize: %v\", errors.Unwrap(err))\n    }\n    return err\n}","preventionTips":["Never close fds 0/1/2 in startup code before daemonize","Reopen closed std fds to /dev/null before exec'ing the job","Check seccomp/apparmor policies permit dup2 in hardened environments","Log raw fds at daemonize entry when debugging EBADF"],"tags":["go","unix","daemonize","dup2","file-descriptor"],"backgroundTag":"dup2-ebadf","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}