ERROR_CANNOT_IMPERSONATE (0x558): Fix in 2 Steps
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
- Check your pipe creation and connection. Make sure you've called
CreateNamedPipewithPIPE_TYPE_MESSAGEorPIPE_TYPE_BYTEand thenConnectNamedPipesuccessfully. You don't need any specific security attributes—NULLis fine for impersonation to work. - Read at least one byte from the pipe before impersonating. After
ConnectNamedPipereturnsTRUE, callReadFilewith 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.
}
}
}
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.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:
- Before connecting the pipe, set the pipe's impersonation level to
SecurityIdentificationusingSetSecurityInfoor pipe attributes. - After
ConnectNamedPipe, useGetNamedPipeClientProcessIdto get the client's PID. - Open the client's process token with
OpenProcessTokenandDuplicateTokenExto 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?