{"record":{"id":"aa4c2d343f72387c","repo":"astrid-runtime/astrid","slug":"windows-named-pipe-endpoint-denied-access-while-wa","errorCode":null,"errorMessage":"Windows named-pipe endpoint denied access while waiting","messagePattern":"Windows named-pipe endpoint denied access while waiting","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/local_transport/windows.rs","lineNumber":201,"sourceCode":"        .map_err(|_| io::Error::other(\"named-pipe wait duration overflow\"))?\n        .max(1);\n    // `WaitNamedPipeW` is synchronous, so isolate it from the async worker.\n    // Each call is capped at 50 ms: cancelling the outer future stops all\n    // retries and leaves at most one short detached blocking wait.\n    tokio::task::spawn_blocking(move || {\n        let ready = unsafe { WaitNamedPipeW(encoded.as_ptr(), milliseconds) };\n        if ready != 0 {\n            return Ok(());\n        }\n        let error = io::Error::last_os_error();\n        match error.raw_os_error().map(i32::cast_unsigned) {\n            // A bounded timeout is the backoff between open attempts.\n            Some(ERROR_SEM_TIMEOUT | ERROR_PIPE_BUSY) => Ok(()),\n            Some(ERROR_FILE_NOT_FOUND) => Err(io::Error::new(\n                io::ErrorKind::NotFound,\n                \"Windows named-pipe endpoint disappeared while waiting\",\n            )),\n            Some(ERROR_ACCESS_DENIED) => Err(io::Error::new(\n                io::ErrorKind::PermissionDenied,\n                \"Windows named-pipe endpoint denied access while waiting\",\n            )),\n            _ => Err(error),\n        }\n    })\n    .await\n    .map_err(|error| io::Error::other(format!(\"named-pipe wait task failed: {error}\")))?\n}\n\npub(super) async fn connect_outcome(path: &Path) -> io::Result<ConnectOutcome> {\n    match connect(path).await {\n        Ok(stream) => Ok(ConnectOutcome::Connected(stream)),\n        Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(ConnectOutcome::Absent),\n        // Named pipes have no stale filesystem node: their namespace object\n        // vanishes with the last server handle. Busy and access-denied both\n        // prove that something owns the name and must never trigger a daemon\n        // boot or unauthenticated fallback.","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/local_transport/windows.rs#L183-L219","documentation":"During the Windows named-pipe open retry loop, ERROR_ACCESS_DENIED from the pipe state check means the endpoint exists but the client is not permitted to access it (the pipe server's ACL denies this user, or the pipe is in a state that refuses new clients). Astrid maps this to io::ErrorKind::PermissionDenied instead of endlessly retrying.","triggerScenarios":"open_client_with_retry -> wait_for_pipe_availability receives GetLastError == ERROR_ACCESS_DENIED while probing the named pipe before a successful connect.","commonSituations":"The pipe server was created with a restrictive SECURITY_ATTRIBUTES denying the current user; the client runs as a different account/service than the server; another process owns the pipe name with exclusive access.","solutions":["Run the client under the same user account (or a group allowed by the pipe ACL) as the named-pipe server","Fix the server to create the pipe with permissive security attributes (NULL security descriptor or a DACL granting the client account FILE_GENERIC_READ/WRITE)","Check for name collisions: another process may have created a pipe with the same name; use a unique pipe name"],"exampleFix":"// before (server)\nCreateNamedPipeW(name, ..., NULL /* default, often restrictive context */);\n// after (server)\nSECURITY_ATTRIBUTES sa = make_dacl_allowing_clients();\nCreateNamedPipeW(name, ..., &sa);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match client.open_with_retry(&pipe).await {\n    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {\n        return Err(anyhow!(\"named pipe access denied: run client as an account allowed by the pipe ACL\"));\n    },\n    other => other?,\n}","preventionTips":["Create the server pipe with a DACL granting the client accounts read/write access","Run client and server under the same user or a shared group","Use unique pipe names to avoid taking over a pipe owned by another process"],"tags":["windows","named-pipes","ipc","permissions"],"backgroundTag":"permission-denied","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}