MSDN says
If the function fails, the return value is WAIT_FAILED. To get extended error information, call GetLastError.
The cod
Closing a handle while the handle is being waited on can also cause undefined behaviour.
If you lack the SYNCHRONIZE privilege on the object, then you cannot wait. WAIT_FAILED will be returned.
I got WAIT_FAILED from WaitForMultipleObjects when passing in an array of thread handles as one of them was a pseudo handle. As ever the immortal Raymond Chen explained, and provided the fix: https://blogs.msdn.microsoft.com/oldnewthing/20141015-00/?p=43843
Passing in a bogus object might cause that.