0X00000558

ERROR_CANNOT_IMPERSONATE (0x558): Fix in 2 Steps

Windows Errors Intermediate 👁 7 views 📅 May 26, 2026

This error means a process tried to impersonate a client via a named pipe before reading any data. The fix is simple: read from the pipe first, then impersonate.

Quick Answer

Read at least one byte from the named pipe using ReadFile before calling ImpersonateNamedPipeClient. That's it. The error is not a security problem—it's a sequencing issue.

Why You're Seeing This

This error trips up a lot of developers (me included, back in 2017 when I was building a Windows service that authenticated remote clients via named pipes). The error code 0X00000558 maps to ERROR_CANNOT_IMPERSONATE, and the full message is: Unable to impersonate using a named pipe until data has been read from that pipe.

The Windows named pipe server model requires the server to read from the pipe before it can impersonate the client. The OS needs to see that the client actually sent data—this triggers the security context to be established. If you call ImpersonateNamedPipeClient right after ConnectNamedPipe, you'll get this error every time. It's not a bug in your code—it's missing a step in the sequence.

This usually shows up when you're building a custom Windows service or a local IPC mechanism where the server needs to act as the client for security operations (like accessing a file or registry key with the client's permissions).

Fix Steps

  1. Check your pipe creation and connection. Make sure you've called CreateNamedPipe with PIPE_TYPE_MESSAGE or PIPE_TYPE_BYTE and then ConnectNamedPipe successfully. You don't need any specific security attributes—NULL is fine for impersonation to work.
  2. Read at least one byte from the pipe before impersonating. After ConnectNamedPipe returns TRUE, call ReadFile with a buffer. Even if the client sends zero bytes, the read itself establishes the impersonation context. Here's the C++ snippet that works:
HANDLE hPipe = CreateNamedPipe(
    L"\\.\pipe\MyPipe",
    PIPE_ACCESS_DUPLEX,
    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
    PIPE_UNLIMITED_INSTANCES,
    4096, 4096, 0, NULL);

if (ConnectNamedPipe(hPipe, NULL))
{
    char buffer[1024];
    DWORD bytesRead;
    // Read first, then impersonate.
    if (ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL))
    {
        if (ImpersonateNamedPipeClient(hPipe))
        {
            // Now you can do actions as the client.
            RevertToSelf();
        }
        else
        {
            // Handle error.
        }
    }
}
  • Make sure the client sends data. If the client never writes to the pipe, ReadFile will hang (in blocking mode) or return ERROR_NO_DATA (in non-blocking mode). The client must write at least something—even a single zero byte works.
  • Handle the case where the client disconnects before reading. If the client calls DisconnectNamedPipe before your server reads, ReadFile will return FALSE with ERROR_PIPE_NOT_CONNECTED. In that case, don't impersonate—just close the handle.
  • Alternative Fix (Advanced)

    If you absolutely cannot read from the pipe (e.g., the protocol doesn't allow an initial message), you can bypass the impersonation entirely by duplicating the client's token manually. This is not recommended because it's complex and less secure, but it's possible:

    1. Before connecting the pipe, set the pipe's impersonation level to SecurityIdentification using SetSecurityInfo or pipe attributes.
    2. After ConnectNamedPipe, use GetNamedPipeClientProcessId to get the client's PID.
    3. Open the client's process token with OpenProcessToken and DuplicateTokenEx to create an impersonation token.

    But honestly? Just make the client send a dummy byte. It's simpler and keeps your code clean.

    Prevention Tip

    Build your named pipe communication so that the client always sends a message first—even if it's a heartbeat or a zero-length payload. Document this in your protocol spec. This avoids the error and also makes the server more predictable. Test with a real client (like a simple C# or Python script) before deploying to production. I've seen this exact error bring down a whole authentication service because the developer assumed ImpersonateNamedPipeClient could be called immediately. It can't. Read first.

    Was this solution helpful?