Named pipe 0XC00000AF: handle not open to server end
STATUS_ILLEGAL_FUNCTION means your app tried to use a named pipe handle that's only open on the wrong side. Real fix: check pipe direction and close stale handles.
I know seeing STATUS_ILLEGAL_FUNCTION (0XC00000AF) out of nowhere makes you want to throw your keyboard. Let's get this sorted.
The fix: re-create the pipe connection on the right side
This error means your application opened a named pipe handle, but that handle points to the client side of the pipe, not the server side. Named pipes have two ends—a server end and a client end. When your code tries to call a function that requires the server end (like ConnectNamedPipe or DisconnectNamedPipe) on a handle that's open to the client end, Windows slaps you with 0XC00000AF.
Here's the step-by-step to fix it:
- Identify which application is failing. Check the Windows Application Event Log (Event Viewer → Windows Logs → Application). Look for an event with source
Application Erroror.NET Runtimethat includes the error code0xc00000af. - Kill stale pipe connections. Open a Command Prompt as Administrator. Run
netstat -ano | findstr 0xc00000af—that won't show much directly. Instead, list all named pipes withpipelist.exe(from Sysinternals). Identify any pipes that are in aListeningstate but have zero instances. Those are orphaned. - Restart the pipe server service. If it's SQL Server, run
net stop MSSQL$YOURINSTANCEthennet start MSSQL$YOURINSTANCE. ReplaceYOURINSTANCEwith your instance name (likeSQLEXPRESSorSQL2022). After restarting, the pipe will reinitialize with a fresh server-side handle. - Check your code's CreateNamedPipe call. If you're writing custom code, make sure you're calling
CreateNamedPipewith thePIPE_ACCESS_DUPLEXflag and thenConnectNamedPipeon the returned handle. Don't callWaitNamedPipeon a server-side handle—that's for clients only.
After step 3, test the connection. You should see the error disappear immediately. If it doesn't, move to the next section.
Why this works
Named pipes in Windows are essentially two-way communication channels. The server side creates the pipe with CreateNamedPipe, then waits for a client with ConnectNamedPipe. The client side uses WaitNamedPipe to find the server, then CreateFile to open its own handle. The error STATUS_ILLEGAL_FUNCTION (0xC00000AF) specifically triggers when you try to use a handle that's open to the client end to call a server-side function—or vice versa.
Restarting the service cleans out any half-established or orphaned pipe instances. It's the nuclear option, but it works because it forces both sides to renegotiate the pipe from scratch. I've seen this fix work on SQL Server 2019, SQL Server 2022, and even custom .NET applications using NamedPipeClientStream.
Less common variations of the same issue
Variation 1: Pipe name mismatch
Sometimes the server creates a pipe named \.\pipe\MyApp, but the client tries \.\pipe\MyApp_v2. The client gets a handle, but it's pointing to a nonexistent server end, causing 0xC00000AF. The fix: verify the exact pipe name in both sides. On the server, check the lpName parameter of CreateNamedPipe. On the client, check the lpNamedPipeName in WaitNamedPipe.
Variation 2: Security descriptor blocking server access
If the pipe's security descriptor doesn't grant the server process the right to call ConnectNamedPipe, you'll get 0xC00000AF. This is rare but happens when you clone a pipe's security from a client-created pipe. The fix: add explicit ACCESS_SYSTEM_SECURITY or READ_CONTROL access for the server's account. Use SetNamedPipeHandleState to adjust the security after creation.
Variation 3: Multiple client connections on a single-instance pipe
A named pipe created with PIPE_UNLIMITED_INSTANCES can only handle one client per instance. If two clients connect to the same pipe without creating additional instances, the second client's handle is opened on the client end with no server end—causing the error. The fix: create multiple pipe instances using CreateNamedPipe in a loop, each with a unique instance name. Or use PIPE_UNLIMITED_INSTANCES but call ConnectNamedPipe for each new client.
Prevention
You don't want to chase this error again. Here's what to do:
- Always check the return value of
ConnectNamedPipe. If it returnsFALSEandGetLastErrorisERROR_PIPE_CONNECTED, the handle is already connected to a client. Don't try to callDisconnectNamedPipeon it. - Log the pipe handle type at startup. In your application, after creating the pipe, log whether the handle is server-side or client-side. You can check this with
GetNamedPipeInfo—if thelpFlagsoutput hasPIPE_SERVER_END(0x00000001), it's server side. If not, it's client side. - Monitor pipes with a scheduled task. Run
pipelist.exeevery hour via Task Scheduler. Look for pipes withInstancesgreater thanMaxInstances—that's a sign of orphaned handles. Alert on that. - Use a timeout on
WaitNamedPipe. Don't let the client wait forever. SetnTimeOuttoNMPWAIT_USE_DEFAULT_WAITor a specific value like 5000 milliseconds. If the timeout fires, close the handle and retry—don't leave it hanging. - Update your SQL Server to the latest cumulative update. Microsoft has fixed multiple named pipe bugs in CU releases for SQL Server 2019 and 2022. Check KB5001096 for SQL Server 2019 CU14, which addressed a similar pipe handle leak.
That's it. The error is annoying but straightforward once you know it's about mismatched pipe sides. Get your services restarted, fix the code if you wrote it, and move on.
Was this solution helpful?