0X8001010F

RPC_E_THREAD_NOT_INIT (0x8001010F): CoInitialize not called

Server & Cloud Intermediate 👁 0 views 📅 Jun 5, 2026

This error means your thread skipped CoInitializeEx before making COM calls. It's common in C# async/await code where background threads miss the init step.

Quick answer

Call CoInitializeEx(ptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE) as the first thing in your thread. In C#, wrap the call in Thread.SetApartmentState(ApartmentState.STA) before starting it.

What's actually happening here

COM requires every thread that calls COM interfaces to initialize the COM library first. That's not optional. The CoInitializeEx call sets up the thread's apartment — either STA (single-threaded apartment) or MTA (multi-threaded apartment). Without it, COM rejects any call with RPC_E_THREAD_NOT_INIT (0x8001010F).

I see this most often in three specific scenarios:

  • C# code using async/await that resumes on a thread-pool thread — those threads don't have COM initialized by default.
  • PowerShell scripts that call COM objects (like New-Object -ComObject Word.Application) from a runspace or background job.
  • C++ code that creates a worker thread with CreateThread and forgets to call CoInitializeEx at the top.

The fix isn't hard, but you have to do it on every thread that touches COM directly.

Fix steps

  1. Identify the offending thread. The stack trace will show the COM call that failed. Look for the thread that's calling into COM without init.
  2. In C++: At the very start of your thread function, call:
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    if (FAILED(hr)) { /* handle error */ }
    // ... your COM calls go here ...
    CoUninitialize();
    Use COINIT_MULTITHREADED if you're sure your COM object supports MTA and you want better performance. But for Office interop and most UI-related COM, stick with COINIT_APARTMENTTHREADED.
  3. In C#: You can't call CoInitializeEx directly from managed code without P/Invoke. The cleaner way is to set the thread's apartment state:
    var thread = new Thread(() =>
    {
        // Your COM calls here
    });
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    If you're using Task.Run, you can't change the apartment state of thread-pool threads. Instead, create a dedicated STA thread and marshal work to it.
  4. In PowerShell: Use -STA switch when starting PowerShell, or wrap COM calls in a scriptblock executed on an STA thread:
    $sta = [System.Threading.Thread]::new({ param($script)
        [System.Threading.Thread]::CurrentThread.SetApartmentState('STA')
        & $script
    })
    $sta.Start({ New-Object -ComObject Word.Application })

Alternative fixes if the main one fails

  • Switch to MTA. If your COM object supports it, call CoInitializeEx(NULL, COINIT_MULTITHREADED). This avoids the STA overhead but requires the object to be thread-safe. Most Office objects are not.
  • Marshal to an STA thread. If you can't change the thread's init (e.g., you're in a library), create a dedicated STA thread that hosts a hidden window and forward COM calls to it via SendMessage or Control.Invoke in .NET.
  • Use the COM object from the main thread. Often the simplest workaround — just don't use background threads for COM calls. But that kills concurrency.

Prevention tip

Always wrap your thread entry points with a guard. In C++, I use a RAII helper that calls CoInitializeEx in the constructor and CoUninitialize in the destructor. Then it's impossible to forget. For .NET, every thread that will call COM should have SetApartmentState called before Start. The pattern of forgetting this is so common that I now lint for it in CI pipelines — a regex check on new Thread without a matching SetApartmentState in the next 5 lines flags it.

Was this solution helpful?