astrid-runtime/astrid · error

named-pipe client's effective token belongs to a different…

Error message

named-pipe client's effective token belongs to a different operating-system user

What it means

During accept, the server impersonates the named-pipe client (ImpersonateNamedPipeClient) and reads the effective token's user SID; if it differs from the server's own user SID the client is rejected. This checks the identity the client is actually exercising on the pipe, complementing the process-owner check.

Solutions

  1. Start the client under the same user account that owns the server pipe.
  2. Check the client isn't impersonating another user before ConnectNamedPipe/CreateFile on the pipe.
  3. Inspect both accounts with `whoami /user` on each side to confirm the SIDs match.
Defensive patterns

Strategy: validation

Validate before calling

// on the client: ensure the process token owner matches the server account
// e.g. verify with GetTokenInformation(TokenOwner) before opening the pipe

Type guard

fn token_owner_matches(client_sid: &Sid, server_sid: &Sid) -> bool {
    client_sid.equals(server_sid)
}

Try / catch

match listener.accept() {
    Err(e) if e.kind() == io::ErrorKind::PermissionDenied
        && e.to_string().contains("effective token") => {
        eprintln!("client token owner mismatch; dropping connection");
    }
    other => other?,
}

Prevention

When it happens

Trigger: accept() called on a server pipe whose connected client's effective security token belongs to a different OS user — e.g. the client connected using a token of another account, or its impersonation token differs from its process owner.

Common situations: Client running under a service account while the server runs as the logged-in user; client started via scheduled task under a different identity; duplicated/impersonated tokens on the client side.

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


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

Appendix: source

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

fn require_current_user_process_peer(stream: &LocalStream) -> io::Result<VerifiedPeerProcess> {
    let peer = peer_process_identity(stream)?;
    if peer.user_sid.equals(&current_user_sid()?) {
        Ok(peer)
    } else {
        Err(io::Error::new(
            io::ErrorKind::PermissionDenied,
            "named-pipe peer process belongs to a different operating-system user",
        ))
    }
}

fn require_current_user_effective_client(stream: &LocalStream) -> io::Result<()> {
    let client_sid = effective_client_user_sid(stream)?;
    if client_sid.equals(&current_user_sid()?) {
        Ok(())
    } else {
        Err(io::Error::new(
            io::ErrorKind::PermissionDenied,
            "named-pipe client's effective token belongs to a different operating-system user",
        ))
    }
}

fn effective_client_user_sid(stream: &LocalStream) -> io::Result<OwnedSid> {
    let server = match &stream.inner {
        StreamInner::Server(server) => server,
        StreamInner::Client(_) => {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "client effective-token validation requires the server pipe end",
            ));
        },
    };
    let impersonated = unsafe { ImpersonateNamedPipeClient(server.as_raw_handle().cast()) };
    if impersonated == 0 {

View on GitHub (pinned to affd8760f4)