sinelaw/fresh · error
Failed to dup stdin
Error message
Failed to dup stdin: {} What it means
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.
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.
Example fix
// before $ fresh 0<&- # stdin closed -> EBADF // after $ fresh < /dev/null # provide a valid stdin
Defensive patterns
Strategy: validation
Validate before calling
// ensure fd 0 is open and usable before launching // shell: [ -e /dev/fd/0 ] && exec fresh // rust: assert!(libc::fcntl(0, libc::F_GETFD) != -1, "stdin closed");
Type guard
fn stdin_is_open() -> bool { unsafe { libc::fcntl(0, libc::F_GETFD) != -1 } } Try / catch
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 } Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13).
Data as JSON: /api/errors/cb22c972496b3275.
Report an issue: GitHub.
Appendix: source
Thrown at crates/fresh-editor/src/main.rs:730
Ok(StdinStreamState {
spool,
thread_handle: Some(thread_handle),
})
}
/// Hand back the piped stdin as an owned reader, so it survives stdin being
/// reopened as the terminal.
#[cfg(unix)]
fn take_stdin_pipe() -> AnyhowResult<std::fs::File> {
use std::os::unix::io::{AsRawFd, FromRawFd};
let stdin_fd = io::stdin().as_raw_fd();
// SAFETY: `dup` returns a fresh descriptor for the same pipe, which the
// `File` below then owns; the original fd is left for `reopen_stdin_from_tty`.
let pipe_fd = unsafe { libc::dup(stdin_fd) };
if pipe_fd == -1 {
anyhow::bail!("Failed to dup stdin: {}", io::Error::last_os_error());
}
// SAFETY: `pipe_fd` is a valid descriptor this function just created and
// hands sole ownership of to the returned `File`.
Ok(unsafe { std::fs::File::from_raw_fd(pipe_fd) })
}
/// Windows counterpart of [`take_stdin_pipe`].
#[cfg(windows)]
fn take_stdin_pipe() -> AnyhowResult<std::fs::File> {
use std::os::windows::io::FromRawHandle;
use windows_sys::Win32::Foundation::{
DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE, INVALID_HANDLE_VALUE,
};
use windows_sys::Win32::System::Console::{GetStdHandle, STD_INPUT_HANDLE};
use windows_sys::Win32::System::Threading::GetCurrentProcess;
// SAFETY: plain console/handle queries; every failure is checked below.
let stdin_handle = unsafe { GetStdHandle(STD_INPUT_HANDLE) };View on GitHub (pinned to 67894ca546)