{"record":{"id":"cb22c972496b3275","repo":"sinelaw/fresh","slug":"failed-to-dup-stdin","errorCode":null,"errorMessage":"Failed to dup stdin: {}","messagePattern":"Failed to dup stdin: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-editor/src/main.rs","lineNumber":730,"sourceCode":"\n    Ok(StdinStreamState {\n        spool,\n        thread_handle: Some(thread_handle),\n    })\n}\n\n/// Hand back the piped stdin as an owned reader, so it survives stdin being\n/// reopened as the terminal.\n#[cfg(unix)]\nfn take_stdin_pipe() -> AnyhowResult<std::fs::File> {\n    use std::os::unix::io::{AsRawFd, FromRawFd};\n\n    let stdin_fd = io::stdin().as_raw_fd();\n    // SAFETY: `dup` returns a fresh descriptor for the same pipe, which the\n    // `File` below then owns; the original fd is left for `reopen_stdin_from_tty`.\n    let pipe_fd = unsafe { libc::dup(stdin_fd) };\n    if pipe_fd == -1 {\n        anyhow::bail!(\"Failed to dup stdin: {}\", io::Error::last_os_error());\n    }\n    // SAFETY: `pipe_fd` is a valid descriptor this function just created and\n    // hands sole ownership of to the returned `File`.\n    Ok(unsafe { std::fs::File::from_raw_fd(pipe_fd) })\n}\n\n/// Windows counterpart of [`take_stdin_pipe`].\n#[cfg(windows)]\nfn take_stdin_pipe() -> AnyhowResult<std::fs::File> {\n    use std::os::windows::io::FromRawHandle;\n    use windows_sys::Win32::Foundation::{\n        DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE, INVALID_HANDLE_VALUE,\n    };\n    use windows_sys::Win32::System::Console::{GetStdHandle, STD_INPUT_HANDLE};\n    use windows_sys::Win32::System::Threading::GetCurrentProcess;\n\n    // SAFETY: plain console/handle queries; every failure is checked below.\n    let stdin_handle = unsafe { GetStdHandle(STD_INPUT_HANDLE) };","sourceCodeStart":712,"sourceCodeEnd":748,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-editor/src/main.rs#L712-L748","documentation":"At startup the editor duplicates the raw stdin file descriptor with libc::dup so a File can own a private handle to the piped input while the original fd is reused for the TTY. If dup fails (returns -1), the OS error is surfaced via this bail.","triggerScenarios":"Launching the editor with stdin not being a valid open descriptor, running with a closed stdin (fd 0 closed), hitting the process fd limit, or operating in an environment where fd duplication is denied (e.g. restricted sandbox/seccomp).","commonSituations":"Running the binary with stdin explicitly closed (myapp 0<&-); spawning under a service manager or sandbox that closes/limits fds; ulimit -n exhausted so dup fails with EMFILE.","solutions":["Run the editor with a valid stdin (a terminal or a pipe), e.g. don't close fd 0.","Check the fd limit (ulimit -n) and raise it if dup failed with EMFILE.","Inspect io::Error::last_os_error() in the message for the specific errno (EBADF/EMFILE/EPERM) and fix the environment accordingly."],"exampleFix":"// before\n$ fresh 0<&-            # stdin closed -> EBADF\n// after\n$ fresh < /dev/null      # provide a valid stdin","handlingStrategy":"validation","validationCode":"// ensure fd 0 is open and usable before launching\n// shell: [ -e /dev/fd/0 ] && exec fresh\n// rust: assert!(libc::fcntl(0, libc::F_GETFD) != -1, \"stdin closed\");","typeGuard":"fn stdin_is_open() -> bool { unsafe { libc::fcntl(0, libc::F_GETFD) != -1 } }","tryCatchPattern":"match dup_stdin() { Err(e) if e.to_string().contains(\"Failed to dup stdin\") => eprintln!(\"run with a valid stdin: fresh < /dev/null\"), r => r }","preventionTips":["Never launch the editor with fd 0 closed; redirect /dev/null instead","Check ulimit -n if dup fails with EMFILE","In sandboxes/containers, verify fd duplication syscalls are permitted"],"tags":["startup","unix","file-descriptor"],"backgroundTag":"file-open-failed","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}