When does this error show up?
You'll see ERROR_WAIT_NO_CHILDREN (error code 0x00000080, decimal 128) when a program calls WaitForMultipleObjects or WaitForSingleObject on a handle that doesn't belong to a valid child process. This usually happens in custom software, scripts, or server tools that spawn child processes and then try to wait for them to finish. A real-world trigger: you wrote a batch script that launches an EXE with START /WAIT, but the child process crashes before the wait call runs. Or a developer uses a CreateProcess call, forgets to check the return value, and the child handle is invalid from the start.
What's actually happening?
Under the hood, Windows keeps a list of active child processes for each parent. When you call a wait function with a process handle, Windows looks up that handle in the internal table. If the handle was never a child (maybe it's a duplicate, or it's from a different session), or if the child already exited and the handle was closed or reused, you get 0x00000080. The kernel is saying: "I've got nothing to wait for here."
The most common cause is bad code — the parent process either doesn't verify that CreateProcess succeeded, or it calls CloseHandle on the child handle too early, then tries to wait on it later. Another classic: a service tries to wait for a process it launched but the process was orphaned to a different job object. Also, if you're using WaitForMultipleObjects and pass a handle array that contains invalid or duplicate entries, the same error can pop up.
The fix: step-by-step for developers
If you wrote the code that triggers this, here's how to fix it. If you're just running the software, skip to the "still failing" section below.
- Check the return value of CreateProcess.
After calling
CreateProcess, always test the return value. If it returnsFALSE, don't try to wait on any handle — the process wasn't created. Here's the check in C++:BOOL bSuccess = CreateProcess(..., &hProcess, &hThread); if (!bSuccess) { // Handle error. Do NOT call WaitForSingleObject on hProcess. printf("CreateProcess failed, error %lu\n", GetLastError()); return; }After this step, you should have a valid
hProcesshandle. If not, fix the reason the process failed to start (wrong path, missing DLL, insufficient permissions). - Don't close the handle before the wait.
Many developers call
CloseHandle(hProcess)right afterCreateProcessbecause they think they're cleaning up. That's a mistake. Once you close the handle, Windows may release the reference, and the handle value can be reused. Later,WaitForSingleObject(hProcess, INFINITE)will either block forever or return WAIT_FAILED with this error. The rule: close the handle only after the wait completes.// Wait first WaitForSingleObject(hProcess, INFINITE); // Then close CloseHandle(hProcess); CloseHandle(hThread);After moving the close after the wait, the error should disappear.
- Use GetExitCodeProcess before waiting.
If you're unsure whether the child already exited, check its exit code first. If the process already terminated,
GetExitCodeProcessreturnsSTILL_ACTIVEonly if it's running. If it's not, you can skip the wait entirely. This prevents the 0x00000080 error when the child finished before the wait call.DWORD dwExitCode; GetExitCodeProcess(hProcess, &dwExitCode); if (dwExitCode == STILL_ACTIVE) { WaitForSingleObject(hProcess, INFINITE); } else { // Process already finished, no need to wait printf("Process already exited with code %lu\n", dwExitCode); }After adding this check, you won't call wait on an already-dead handle.
- Verify the handle type.
If you're passing handles from
DuplicateHandleor from another process, make sure they're valid process handles. UseWaitForMultipleObjectswith the right flags — don't mix event handles with process handles in the same array. A simple test: print the handle value before the wait to see if it's NULL or INVALID_HANDLE_VALUE (-1).if (hProcess == NULL || hProcess == INVALID_HANDLE_VALUE) { printf("Invalid handle passed to wait\n"); }If you find invalid handles here, trace back to where they're created or duplicated.
- For batch scripts: use START /WAIT correctly.
In a batch file, if you write
START /WAIT notepad.exe, that works fine. But if you useSTART /WAIT call myapp.exe, theCALLmight interfere. The right way is simply:START /WAIT myapp.exe echo %ERRORLEVEL%After running this,
ERRORLEVELshows the child's exit code, and you won't see the 0x00000080 error.
What to check if it still fails
If you've verified the code and still see 0x00000080, check these:
- Job objects and sandboxing. If your app runs under a job object (like in some enterprise security software), the child process might be assigned to the job, not to your parent process. The wait function can't find it. Run the app outside the job to test.
- Antivirus interference. Some security tools intercept
CreateProcessand can replace the child's handle with a dummy. Temporarily disable the AV to see if the error goes away. - 64-bit vs 32-bit mismatch. If you're running a 32-bit parent that spawns a 64-bit child (or vice versa), handle sharing can break. Make sure both are compiled for the same architecture, or use WOW64 properly.
- Event log. Open Event Viewer -> Windows Logs -> Application. Look for warnings or errors around the time the error occurred. You might see a source like "Application Error" or ".NET Runtime" with more details.
- Sysinternals Process Monitor. Use Procmon to filter for your process. Watch for
CreateProcesscalls that fail, orWaitForSingleObjectcalls that return immediately. This gives you the exact sequence of operations.
If none of that works, you're likely dealing with a bug in a third-party library or a corrupted OS. A clean boot (disable all non-Microsoft services) will tell you if something else is interfering.