LGUG2Z/komorebi · error

could not find next window

Error message

could not find next window

What it means

top_visible_window walks the z-order with GetWindow/GW_HWNDNEXT looking for the next visible top-level window. If the enumeration exhausts without finding one, komorebi bails with 'could not find next window'. It indicates no visible sibling window was reachable in the z-order chain.

Source

Thrown at komorebi/src/windows_api.rs:762

        )?;

        Ok(hwnds)
    }

    #[allow(dead_code)]
    pub fn top_visible_window() -> eyre::Result<isize> {
        let hwnd = Self::top_window()?;
        let mut next_hwnd = hwnd;

        while next_hwnd != 0 {
            if Self::is_window_visible(next_hwnd) {
                return Ok(next_hwnd);
            }

            next_hwnd = Self::next_window(next_hwnd)?;
        }

        bail!("could not find next window")
    }

    pub fn window_rect(hwnd: isize) -> eyre::Result<Rect> {
        let mut rect = unsafe { std::mem::zeroed() };

        if Self::dwm_get_window_attribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &mut rect).is_ok() {
            // TODO(raggi): once we declare DPI awareness, we will need to scale the rect.
            // let window_scale = unsafe { GetDpiForWindow(hwnd) };
            // let system_scale = unsafe { GetDpiForSystem() };
            // Ok(Rect::from(rect).scale(system_scale.try_into()?, window_scale.try_into()?))
            Ok(Rect::from(rect))
        } else {
            unsafe { GetWindowRect(HWND(as_ptr!(hwnd)), &mut rect) }.process()?;
            Ok(Rect::from(rect))
        }
    }

    /// shadow_rect computes the offset of the shadow position of the window to

View on GitHub (pinned to e0709f02bf)

Solutions

  1. Check that at least one visible, non-minimized window exists on the target monitor before calling
  2. Enumerate windows with IsWindowVisible filtering yourself to confirm state
  3. Restart or rescan komorebi's window management state
  4. Handle the empty-workspace case in your caller instead of treating it as fatal

Example fix

// before
let hwnd = WindowsApi::top_visible_window(start)?;
// after
let hwnd = match WindowsApi::top_visible_window(start) {
    Ok(h) => h,
    Err(_) => return Ok(()), // empty/hidden workspace is not fatal
};
Defensive patterns

Strategy: try-catch

Validate before calling

// Check at least one visible window exists first
fn has_visible_window() -> bool {
    !komorebi_state().windows.iter().any(|w| w.visible) == false
}

Try / catch

match WindowsApi::top_visible_window(hwnd) {
    Ok(next) => use(next),
    Err(e) if e.to_string().contains("could not find next window") => {
        log::debug!("no visible window in z-order; treating workspace as empty");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling WindowsApi::top_visible_window(hwnd) when the starting hwnd is the last in the z-order, all subsequent windows are invisible/minimized, or the hwnd is invalid so the loop immediately fails to find a next window.

Common situations: All windows on a monitor are minimized or hidden; a window was destroyed mid-enumeration; querying a virtual desktop whose windows are all cloaked; empty workspaces in multi-monitor setups.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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