LGUG2Z/komorebi · critical

creating RENDER_FACTORY failed

Error message

creating RENDER_FACTORY failed

What it means

The border renderer lazily initializes a Direct2D render factory on first use via D2D1CreateFactory in a LazyLock. If COM/D2D1 factory creation fails, the expect panics with this message and the whole komorebi process dies. D2D1CreateFactory fails only in abnormal system conditions since it just allocates a factory object.

Source

Thrown at komorebi/src/border_manager/border.rs:103

pub struct RenderFactory(ID2D1Factory);
unsafe impl Sync for RenderFactory {}
unsafe impl Send for RenderFactory {}

impl Deref for RenderFactory {
    type Target = ID2D1Factory;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[allow(clippy::expect_used)]
static RENDER_FACTORY: LazyLock<RenderFactory> = unsafe {
    LazyLock::new(|| {
        RenderFactory(
            D2D1CreateFactory::<ID2D1Factory>(D2D1_FACTORY_TYPE_MULTI_THREADED, None)
                .expect("creating RENDER_FACTORY failed"),
        )
    })
};

static BRUSH_PROPERTIES: LazyLock<D2D1_BRUSH_PROPERTIES> =
    LazyLock::new(|| D2D1_BRUSH_PROPERTIES {
        opacity: 1.0,
        transform: Matrix3x2::identity(),
    });

/// Apply a new tracked rect to the border on its own message-loop thread.
/// Updates `window_rect`, calls `set_position`, and re-renders if size/position
/// changed. Used by both `EVENT_OBJECT_LOCATIONCHANGE` (real window movements)
/// and `WM_ANIMATE_RECT` (animation-driven movements while the source is cloaked).
///
/// SAFETY: caller must ensure `border_pointer` is non-null, points to a live
/// `Border`, and that we are running on the border's WndProc thread.
unsafe fn apply_tracked_rect(border_pointer: *mut Border, rect: Rect) {

View on GitHub (pinned to e0709f02bf)

Solutions

  1. Verify Windows has Direct2D/DirectX runtime components installed (install Desktop Experience / graphics feature on Server SKUs, run sfc /scannow to repair system files)
  2. Update GPU drivers and confirm D2D1.dll exists in System32
  3. Ensure the calling thread is COM-initialized (CoInitializeEx) before the factory is created if used off the main thread
  4. Update komorebi to the latest version; report as a bug with Windows version details if the system is a normal desktop install
  5. As a workaround, disable the border feature (komorebic border disable) so RENDER_FACTORY is never initialized
Defensive patterns

Strategy: try-catch

Validate before calling

// PowerShell: verify D2D1.dll present before running komorebi
if (-not (Test-Path "$env:SystemRoot\System32\d2d1.dll")) {
  throw "Direct2D runtime missing; install Desktop Experience / repair Windows"
}

Try / catch

// Make factory creation fallible and degrade gracefully
static RENDER_FACTORY: LazyLock<Result<RenderFactory, String>> = LazyLock::new(|| {
    unsafe { D2D1CreateFactory::<ID2D1Factory>(D2D1_FACTORY_TYPE_MULTI_THREADED, None) }
        .map(RenderFactory)
        .map_err(|e| e.to_string())
});
// at use site: if let Err(e) = *RENDER_FACTORY { log::warn!("borders unavailable: {e}"); return; }

Prevention

When it happens

Trigger: First render of the window border triggers LazyLock::new, which calls D2D1CreateFactory::<ID2D1Factory>(D2D1_FACTORY_TYPE_MULTI_THREADED, None); it returns Err when COM is not initialized in the calling thread/apartment, D2D1.dll is missing or corrupted, or on systems where Direct2D/DirectX components are unavailable (e.g. Server Core, broken graphics drivers).

Common situations: Running komorebi on Windows Server Core or a stripped VM without Direct2D/DirectX runtime components; corrupted Windows graphics stack after a failed update; running in an environment where COM initialization failed; out-of-memory during factory creation.

Related errors


AI-assisted analysis of LGUG2Z/komorebi@e0709f02bf (2026-09-06). Data as JSON: /api/errors/6fe9794c0ce38aee. Report an issue: GitHub.