Quick answer
ERROR_PIPE_CONNECTED (0x217) means your ConnectNamedPipe call failed because a client already connected before you called it. The fix is to handle the ERROR_PIPE_CONNECTED return as a success case and process the connection normally.
Why this happens
Named pipes on Windows are built for speed, and the API works in a specific rhythm: you create a pipe instance with CreateNamedPipe, then wait for a client with ConnectNamedPipe. The race occurs when a client connects between those two calls. Since the pipe is already connected, ConnectNamedPipe returns 0 with GetLastError set to ERROR_PIPE_CONNECTED.
This is a classic non-issue for experienced Windows developers—you don't need to treat it as a failure. The connection is ready. But if you blindly check for success and bail on any zero return, you'll drop perfectly good connections and see this error in your logs.
I've seen this most often in high-frequency client connections: a service that accepts bursts of short-lived pipe clients, or a server that creates a new pipe instance only after the previous one disconnects. The window is tiny, but it exists, and under load it hits constantly.
Fix steps
- Check for
ERROR_PIPE_CONNECTEDafterConnectNamedPipefails. The standard pattern is:
BOOL connected = ConnectNamedPipe(hPipe, NULL);
if (!connected) {
DWORD err = GetLastError();
if (err != ERROR_PIPE_CONNECTED) {
// real error, clean up
CloseHandle(hPipe);
continue;
}
// else: connection is already there, proceed
}
// handle the connectionThe reason this works: the pipe is in a connected state, so you can read and write right away. No need to call anything else.
- Use the overlapped (async) version of
ConnectNamedPipeif you're building a multi-client server. With overlapped I/O, you pass anOVERLAPPEDstructure. When the operation completes, you get a status ofERROR_PIPE_CONNECTEDinGetOverlappedResult—even if it succeeded. That trips up a lot of people. The same rule applies: treat that error code as success. - If you're using .NET, check the
PipeStream.IsConnectedproperty before waiting. Actually, .NET handles this internally forNamedPipeServerStream—you rarely see this error there. This is mostly a C/C++ issue, but if you're doing P/Invoke, same rules apply.
Alternative fixes if the main one doesn't resolve it
- Close the pipe handle and recreate the instance. If you're seeing this error repeatedly and it's not just a race, you might have a leftover connection from a previous operation. Close the handle and call
CreateNamedPipeagain. - Check if you're using a duplex pipe with a client that connects twice. A client that opens two handles to the same pipe name can cause unexpected connections. Audit your client code.
- Make sure you're not calling
ConnectNamedPipeon a pipe that's already connected. It's easy to call it twice in a loop. Track connection state with a boolean.
Prevention
Treat ERROR_PIPE_CONNECTED as a normal success path in your code, and you'll never see it as a problem again. Also consider using WaitNamedPipe on the client side to reduce the race window—it ensures the client waits for the server to be ready before connecting.
One more thing: if you're writing a service that restarts a lot, use a unique pipe name per instance (append a GUID or process ID). That avoids stale connections from old instances entirely.