astrid-runtime/astrid · error

Windows named-pipe endpoint disappeared while waiting

Error message

Windows named-pipe endpoint disappeared while waiting

What it means

While a Windows named-pipe client is waiting for a busy server endpoint to become available, the retry loop checks the pipe state; ERROR_FILE_NOT_FOUND means the pipe endpoint no longer exists at all, so further waiting is pointless. Astrid surfaces this as io::ErrorKind::NotFound. It typically means the server stopped listening (pipe server closed) while the client was backing off between open attempts.

Source

Thrown at crates/astrid-core/src/local_transport/windows.rs:197

async fn wait_for_pipe_availability(pipe_name: &OsStr, wait: Duration) -> io::Result<()> {
    let encoded = wide_nul(pipe_name);
    let milliseconds = u32::try_from(wait.as_millis())
        .map_err(|_| io::Error::other("named-pipe wait duration overflow"))?
        .max(1);
    // `WaitNamedPipeW` is synchronous, so isolate it from the async worker.
    // Each call is capped at 50 ms: cancelling the outer future stops all
    // retries and leaves at most one short detached blocking wait.
    tokio::task::spawn_blocking(move || {
        let ready = unsafe { WaitNamedPipeW(encoded.as_ptr(), milliseconds) };
        if ready != 0 {
            return Ok(());
        }
        let error = io::Error::last_os_error();
        match error.raw_os_error().map(i32::cast_unsigned) {
            // A bounded timeout is the backoff between open attempts.
            Some(ERROR_SEM_TIMEOUT | ERROR_PIPE_BUSY) => Ok(()),
            Some(ERROR_FILE_NOT_FOUND) => Err(io::Error::new(
                io::ErrorKind::NotFound,
                "Windows named-pipe endpoint disappeared while waiting",
            )),
            Some(ERROR_ACCESS_DENIED) => Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                "Windows named-pipe endpoint denied access while waiting",
            )),
            _ => Err(error),
        }
    })
    .await
    .map_err(|error| io::Error::other(format!("named-pipe wait task failed: {error}")))?
}

pub(super) async fn connect_outcome(path: &Path) -> io::Result<ConnectOutcome> {
    match connect(path).await {
        Ok(stream) => Ok(ConnectOutcome::Connected(stream)),
        Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(ConnectOutcome::Absent),

View on GitHub (pinned to affd8760f4)

Solutions

  1. Verify the server process is still running and re-creating its named-pipe listener; restart it if it died
  2. Retry the connection from scratch (re-resolve the endpoint) rather than reusing a stale pipe path
  3. Confirm the pipe name matches exactly what the server creates (case and \\pipe\ prefix)

Example fix

// before
let stream = client.open_with_retry(&path).await?; // fails if server dies mid-retry
// after
let stream = match client.open_with_retry(&path).await {
    Err(e) if e.kind() == io::ErrorKind::NotFound => {
        ensure_server_running()?;
        client.open_with_retry(&path).await?
    },
    other => other?,
};
Defensive patterns

Strategy: retry

Try / catch

match client.open_with_retry(&pipe).await {
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
        ensure_server_alive()?;            // pipe vanished: restart server / re-resolve
        client.open_with_retry(&pipe).await?
    },
    other => other?,
}

Prevention

When it happens

Trigger: open_client_with_retry -> wait_for_pipe_availability observes GetLastError == ERROR_FILE_NOT_FOUND for the named pipe path, i.e. the pipe was busy/denied earlier but is now gone before a successful open.

Common situations: The Astrid server process exited or cancelled its CreateNamedPipe listener while a client was retrying; a service restart raced with a connecting client; wrong pipe name that briefly existed from another process.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/e1ca107fafbd915e. Report an issue: GitHub.