astrid-runtime/astrid · error
Windows named-pipe endpoints are kernel-owned and cannot be
Error message
Windows named-pipe endpoints are kernel-owned and cannot be removed while live
What it means
On Windows, named-pipe server endpoints created via CreateNamedPipe are owned by the kernel, not the filesystem, so there is no file to unlink. remove_endpoint refuses to fake a delete and returns PermissionDenied when the endpoint still exists, succeeding only when it is already gone (e.g. after all handles were closed).
Source
Thrown at crates/astrid-core/src/local_transport/windows.rs:351
EndpointState::Available => Ok(()),
EndpointState::Absent => Err(io::Error::new(
io::ErrorKind::NotFound,
"Windows named-pipe endpoint is absent",
)),
EndpointState::BusyOrDenied => Err(io::Error::new(
io::ErrorKind::WouldBlock,
"Windows named-pipe endpoint is occupied but unavailable",
)),
}
}
pub(super) fn endpoint_is_present(path: &Path) -> io::Result<bool> {
Ok(!matches!(endpoint_state(path)?, EndpointState::Absent))
}
pub(super) fn remove_endpoint(path: &Path) -> io::Result<()> {
if endpoint_is_present(path)? {
return Err(io::Error::new(
io::ErrorKind::PermissionDenied,
"Windows named-pipe endpoints are kernel-owned and cannot be removed while live",
));
}
Ok(())
}
pub(super) fn remove_stale_endpoint(path: &Path) -> io::Result<bool> {
// Unlike a Unix socket pathname, a named-pipe endpoint cannot remain stale
// after its final server handle closes. Never delete or replace an object
// merely because its DACL makes it inaccessible.
let _ = endpoint_state(path)?;
Ok(false)
}
pub(super) fn peer_is_current_user(stream: &LocalStream) -> io::Result<bool> {
if matches!(&stream.inner, StreamInner::Server(_)) {
return Ok(effective_client_user_sid(stream)?.equals(¤t_user_sid()?));View on GitHub (pinned to affd8760f4)
Solutions
- Drop (or close) the server-side stream/listener first so all pipe handles are released, then call remove_endpoint.
- If you only want cleanup, make the remove best-effort: ignore PermissionDenied since the kernel deletes the pipe automatically once the last handle closes.
- Restructure so remove_endpoint is called only after confirming endpoint_is_present returns false.
Example fix
// before
server.shutdown();
transport.remove_endpoint(&path)?;
// after
drop(server); // releases the kernel-owned pipe
if transport.endpoint_is_present(&path)? {
transport.remove_endpoint(&path)?;
} Defensive patterns
Strategy: try-catch
Validate before calling
// check before attempting removal
if !endpoint_is_present(&path)? { /* nothing to remove; skip */ } Type guard
fn can_remove(t: &Transport, p: &Path) -> bool {
!t.endpoint_is_present(p).unwrap_or(true)
} Try / catch
match transport.remove_endpoint(&path) {
Ok(()) => {}
Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {
// pipe still kernel-owned; it disappears when the last handle drops
eprintln!("endpoint still live; skipping unlink");
}
Err(e) => return Err(e),
} Prevention
- Always drop the server stream before cleanup/unlink logic.
- Treat endpoint removal as best-effort on Windows — pipes vanish with their last handle.
- Add a shutdown test asserting remove_endpoint succeeds after the listener is dropped.
When it happens
Trigger: Calling remove_endpoint(path) while a bound NamedPipeServer (or any handle to the pipe instance) is still open; endpoint_state reports the pipe as present.
Common situations: Cleanup code in Drop or shutdown handlers that removes the endpoint file before/without dropping the server listener; ported Unix code that unlinks a Unix domain socket path on shutdown; leaked server handles keeping the pipe alive after the app 'finished'.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- Windows named-pipe endpoint disappeared while waiting
- Windows named-pipe endpoint denied access while waiting
- named-pipe client disconnected before transport authenticati
- Windows named-pipe endpoint is absent
- Windows named-pipe endpoint is occupied but unavailable
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/35cfcfd9ac381d04.
Report an issue: GitHub.