zellij-org/zellij · critical

failed to accept reply connection

Error message

failed to accept reply connection

What it means

Windows-only accept path: after a client connects to the main ipc socket, the server accepts the paired reply connection on the second named pipe bound via ipc_bind_reply, and this expect treats an accept error as fatal. The failure is almost always a pipe-state race - the client died between connecting to the main socket and the reply accept, the pipe handle was closed, or third-party software interfered with the named pipe. It runs inside the per-connection branch of the listener loop, so one bad accept panics the whole server accept thread.

Source

Thrown at zellij-server/src/lib.rs:943

                // It is not guaranteed that all platforms allow setting the sticky bit on sockets!
                #[cfg(unix)]
                drop(set_permissions(&socket_path, 0o1700));

                // On Windows, named pipes are half-duplex, so we need a separate
                // reply pipe for server→client messages.
                #[cfg(windows)]
                let reply_listener = zellij_utils::consts::ipc_bind_reply(&socket_path).unwrap();

                for stream in listener.incoming() {
                    match stream {
                        Ok(stream) => {
                            let mut os_input = os_input.clone();
                            let client_id = session_state.write().unwrap().new_client();

                            #[cfg(windows)]
                            let reply_stream = reply_listener
                                .accept()
                                .expect("failed to accept reply connection");

                            #[cfg(windows)]
                            let receiver = os_input
                                .new_client_with_reply(client_id, stream, reply_stream)
                                .unwrap();
                            #[cfg(not(windows))]
                            let receiver = os_input.new_client(client_id, stream).unwrap();

                            let session_data = session_data.clone();
                            let session_state = session_state.clone();
                            let to_server = to_server.clone();
                            thread::Builder::new()
                                .name("server_router".to_string())
                                .spawn(move || {
                                    route_thread_main(
                                        session_data,
                                        session_state,
                                        os_input,

View on GitHub (pinned to 98a0837077)

Solutions

  1. Clear stale zellij ipc artifacts (the zellij socket temp dir) and retry the attach
  2. Make sure client and server are the exact same zellij version - a mismatched handshake can drop the client
  3. Temporarily exclude zellij from antivirus/EDR named-pipe interception to test
  4. If the client itself crashes on connect, reproduce with logging and report it - the accept failure is then a symptom, not the cause

Example fix

// before
let reply_stream = reply_listener
    .accept()
    .expect("failed to accept reply connection");

// after - tolerate a lost client instead of killing the listener
let reply_stream = match reply_listener.accept() {
    Ok(s) => s,
    Err(e) => {
        log::error!("reply accept failed ({e}); client likely vanished");
        continue;
    }
};
Defensive patterns

Strategy: retry

Try / catch

let mut attempts = 0;
let reply_stream = loop {
    match reply_listener.accept() {
        Ok(s) => break s,
        Err(e) if attempts < 3 => {
            attempts += 1;
            log::warn!("reply accept retry {attempts}: {e}");
            std::thread::sleep(std::time::Duration::from_millis(50));
        }
        Err(e) => {
            log::error!("reply accept failed permanently: {e}; dropping this client");
            continue; // drop this client, keep the listener alive
        }
    }
};

Prevention

When it happens

Trigger: A Windows client that connects to the main socket but crashes or exits before the reply pipe is accepted; a stale pipe object from a previous server; antivirus/EDR hooking named pipes and breaking the handshake.

Common situations: Attaching from a client that dies mid-handshake; leftover pipes in the temp dir after unclean shutdown; security software intercepting IPC.

Related errors


AI-assisted analysis of zellij-org/zellij@98a0837077 (2026-08-16). Data as JSON: /api/errors/c9014bc0e4d8fade. Report an issue: GitHub.