sinelaw/fresh · error

Failed to open CONIN$

Error message

Failed to open CONIN$: {}

What it means

On Windows, the editor opens CONIN$ (the console input device) with CreateFileW to use as a fresh stdin source. If CreateFileW returns INVALID_HANDLE_VALUE the OS error is reported. This happens when no console is attached to the process or access to the console device is denied.

Solutions

  1. Run the editor from a console session (cmd/Windows Terminal) so CONIN$ exists
  2. Allocate a console first with AllocConsole or attach to the parent's console with AttachConsole(ATTACH_PARENT_PROCESS)
  3. For ssh scenarios, request a PTY/pseudo-terminal allocation (ssh -t)
  4. Check the reported last_os_error for access-denied and adjust how the process is spawned

Example fix

// before
let conin_handle = unsafe { CreateFileW(CONIN$, GENERIC_READ|GENERIC_WRITE, SHARE_RW, null, OPEN_EXISTING, 0, null_mut()) };
// after
unsafe { AllocConsole(); } // ensure a console exists before opening CONIN$
let conin_handle = unsafe { CreateFileW(CONIN$, GENERIC_READ|GENERIC_WRITE, SHARE_RW, null, OPEN_EXISTING, 0, null_mut()) };
if conin_handle == INVALID_HANDLE_VALUE {
    anyhow::bail!("Failed to open CONIN$: {}", io::Error::last_os_error());
}
Defensive patterns

Strategy: fallback

Validate before calling

fn console_attached() -> bool {
    unsafe { GetConsoleWindow() != std::ptr::null_mut() }
}

Type guard

fn is_valid_handle(h: HANDLE) -> bool { h != INVALID_HANDLE_VALUE && !h.is_null() }

Try / catch

match open_conin() {
    Ok(h) => use_conin(h),
    Err(e) => { unsafe { AllocConsole(); } retry_or_report(e) }
}

Prevention

When it happens

Trigger: CreateFileW("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, security_attributes, OPEN_EXISTING, 0, null) returns INVALID_HANDLE_VALUE — typically when the process has no attached console.

Common situations: Launching the editor from a GUI/launcher without a console, from a Windows service, or in an environment where console devices are unavailable (some ssh sessions without terminal allocation).

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/efd537c931a7a054. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor/src/main.rs:835

    // "CONIN$" is the console input device on Windows
    // This is analogous to /dev/tty on Unix
    let conin: Vec<u16> = "CONIN$\0".encode_utf16().collect();

    let conin_handle = unsafe {
        CreateFileW(
            conin.as_ptr(),
            FILE_GENERIC_READ,
            FILE_SHARE_READ,
            std::ptr::null(),
            OPEN_EXISTING,
            0,
            std::ptr::null_mut(),
        )
    };

    if conin_handle == INVALID_HANDLE_VALUE {
        anyhow::bail!("Failed to open CONIN$: {}", io::Error::last_os_error());
    }

    // Replace stdin with the console input handle
    let success = unsafe { SetStdHandle(STD_INPUT_HANDLE, conin_handle) };
    if success == 0 {
        anyhow::bail!(
            "Failed to set stdin to CONIN$: {}",
            io::Error::last_os_error()
        );
    }

    Ok(())
}

fn handle_first_run_setup(
    editor: &mut Editor,
    args: &Args,
    file_locations: &[FileLocation],

View on GitHub (pinned to 67894ca546)