0XC000070D

STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED Fix

This error means a thread pool callback failed to release a mutex after completion. It's a bug in your code or a driver. Here's how to trace and fix it.

Quick answer (for advanced users)

This error means a thread pool callback function returned without releasing a mutex that it acquired. The owning thread probably terminated or the callback logic has a path that skips the release. Use WinDbg with !analyze -v to get the callback address, then check your code or driver for missing ReleaseMutex() calls.

What's really going on here

I know this error code looks like a cryptic mess. But here's the core problem: Windows thread pools expect strict protocol. When a callback acquires a mutex via SetEventWhenCallbackReturns or ReleaseMutexWhenCallbackReturns, the system tracks that mutex. If the callback exits without releasing it — maybe because an exception blew through your cleanup, or because a thread was terminated — the kernel throws this STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED error. I've seen this most often in custom Windows services and third-party drivers that misuse the thread pool API. On Windows 10 20H2 and later, the error also pops up in buggy anti-cheat drivers.

Step-by-step fix

  1. Capture a crash dump.
    When the error hits, you'll get a blue screen or an event log entry in System log with source "BugCheck" and parameter showing 0xC000070D. If you don't have a dump, configure Windows to create a kernel dump: go to System Properties > Advanced > Startup and Recovery > select "Kernel memory dump". Then reproduce the error.
  2. Load the dump in WinDbg.
    Open the dump file with WinDbg (download from Microsoft Store if you don't have it). Run !analyze -v. Look for the BUGCHECK_CODE — it should confirm 0xC000070D. The output will show a stack trace. Pay attention to the THREADPOOL_CALLBACK_ROUTINE entry. That's your callback address.
  3. Identify the callback.
    Use ln <address> on that callback address. It'll resolve to a function name in your code or a driver. For example, ln 0xfffff80012345678 might show MyDriver!WorkerCallback. That's where the bug lives.
  4. Fix the missing release.
    Open the source code for that callback. Look for every path where ReleaseMutex() or ReleaseMutexWhenCallbackReturns() should be called. Common mistakes:
    • Early return without cleanup.
    • Swallowing exceptions with try/catch but forgetting to release.
    • Calling TerminateThread on the thread pool thread (never do this).
    Add a ReleaseMutex() call in a __finally block or use RAII wrappers.
  5. If it's a driver, check for PnP or power callbacks.
    Drivers that register for IoRegisterPlugPlayNotification or power IRPs often use thread pool callbacks. One missed release in a D0 entry routine can trigger this. Update your driver to use ExReleaseFastMutex or proper cleanup.

Alternative fixes if the main one fails

  • Disable the offending driver temporarily.
    Use Autoruns from Sysinternals to disable suspicious third-party drivers, especially anti-cheat software like BattlEye or EasyAntiCheat. These are frequent culprits on Windows 11 22H2. If the error stops, you've found the source.
  • Update your BIOS and chipset drivers.
    Old firmware can cause weird thread pool corruption. Go to your motherboard vendor's site and grab the latest chipset driver. On Intel systems with Management Engine, update MEI too.
  • Run a system file check.
    Open Command Prompt as admin and type sfc /scannow. Then dism /online /cleanup-image /restorehealth. Corrupted system files can break thread pool internals, though this is rare for this specific error.
  • Check for memory corruption.
    Use mdsched.exe to run a memory test. Bad RAM can cause thread pool structures to go haywire. Let it run for a full pass.

How to prevent it from happening again

Once you've fixed the specific bug, set up a rule: every callback that acquires a mutex must use a structured exception handler (SEH). Wrap the callback body in __try/__finally and put ReleaseMutex() in the __finally block. This way, even if an access violation or division-by-zero occurs, the mutex gets released. Also, never use TerminateThread on thread pool threads — it kills the cleanup. Finally, test your code with Driver Verifier on if you're writing kernel code. Verifier's ThreadPool checks catch these leaks immediately.

Real world trigger: I fixed a help desk server running Windows Server 2019 that got this error every time a user connected via RDP. Turned out a third-party screen recording driver had a callback that returned early when the session switched, forgetting to release a mutex. A vendor patch fixed it.
Related Errors in Windows Errors
0XC0000264 STATUS_RESOURCE_NOT_OWNED (0XC0000264) Fix Guide 0X000009C4 Fix 0X000009C4 MS-DOS error code on legacy apps 0X000020E4 Fix ERROR_DS_CANT_FIND_EXPECTED_NC (0X000020E4) fast 0XC00A0013 STATUS_CTX_LICENSE_NOT_AVAILABLE (0XC00A0013) – Quick Fix Guide

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.