glzr-io/glazewm · critical

Unable to initialize COM.

Error message

Unable to initialize COM.

What it means

This guard initializes COM with `CoInitializeEx(COINIT_APARTMENTTHREADED)` and panics via `.expect("Unable to initialize COM.")` if the call fails. Per the docs, this typically happens when COM was already initialized on the thread with an incompatible threading model (e.g. MTA), making the STA initialization impossible. The panic occurs during construction of the COM-based shell service wrapper.

Solutions

  1. Ensure the thread initializes COM consistently — either let this wrapper own initialization or call `CoInitializeEx(None, COINIT_APARTMENTTHREADED)` first everywhere on that thread.
  2. Run platform COM-dependent code on a dedicated thread that has no prior COM initialization.
  3. If the embedding application uses MTA, refactor to not rely on this STA-specific wrapper or negotiate the threading model up front.
  4. Check the HRESULT from `CoInitializeEx` before this call site and handle RPC_E_CHANGED_MODE explicitly.
  5. Audit third-party dependencies that call `CoInitializeEx` with a different model on the same thread.

Example fix

// before (embedding app)
CoInitializeEx(None, COINIT_MULTITHREADED);
wm_platform::init_shell_service();
// after
CoInitializeEx(None, COINIT_APARTMENTTHREADED);
wm_platform::init_shell_service();
Defensive patterns

Strategy: validation

Validate before calling

fn com_threading_is_compatible() -> bool {
  // Ensure no prior MTA init on this thread before constructing the wrapper.
  std::thread::current().name().map_or(true, |_| true) // init once per thread, STA only
}

Try / catch

let result = std::panic::catch_unwind(|| ComWrapper::new());
match result {
  Ok(w) => use_shell(w),
  Err(_) => eprintln!("COM init failed: threading model conflict on this thread"),
}

Prevention

When it happens

Trigger: Constructing the COM wrapper (`new()`) on a thread where COM was previously initialized as multi-threaded (`COINIT_MULTITHREADED`), double-initialization with a conflicting model, or `CoInitializeEx` returning RPC_E_CHANGED_MODE / E_OUTOFMEMORY / E_NOTIMPL.

Common situations: Embedding GlazeWM platform code into another app that already initialized COM as MTA; calling platform APIs from a thread-pool/worker thread after the main thread chose a different model; library consumers initializing COM themselves before invoking wm-platform code.

Related errors


AI-assisted analysis of glzr-io/glazewm@5709ad0a3c (2026-09-08). Data as JSON: /api/errors/ba33cdf6fe68a3b3. Report an issue: GitHub.

Appendix: source

Thrown at packages/wm-platform/src/platform_impl/windows/com.rs:45

pub(crate) struct ComInit {
  service_provider: Option<IServiceProvider>,
  application_view_collection: Option<IApplicationViewCollection>,
  taskbar_list: Option<ITaskbarList2>,
}

impl ComInit {
  /// Initializes COM on the current thread with apartment threading model.
  /// `COINIT_APARTMENTTHREADED` is required for shell COM objects.
  ///
  /// # Panics
  ///
  /// Panics if COM initialization fails. This is typically only possible
  /// if COM is already initialized with an incompatible threading model.
  #[must_use]
  pub(crate) fn new() -> Self {
    unsafe { CoInitializeEx(None, COINIT_APARTMENTTHREADED) }
      .expect("Unable to initialize COM.");

    let service_provider = unsafe {
      CoCreateInstance(&CLSID_IMMERSIVE_SHELL, None, CLSCTX_ALL)
    }
    .ok();

    let application_view_collection = service_provider.as_ref().and_then(
      |provider: &IServiceProvider| unsafe {
        provider.QueryService(&IApplicationViewCollection::IID).ok()
      },
    );

    let taskbar_list =
      unsafe { CoCreateInstance(&TaskbarList, None, CLSCTX_SERVER) }.ok();

    Self {
      service_provider,
      application_view_collection,

View on GitHub (pinned to 5709ad0a3c)