gitbutlerapp/gitbutler · error · Error
window.ResizeObserver is missing.
Error message
window.ResizeObserver is missing.
What it means
Scrollbar.svelte's setupViewport requires window.ResizeObserver to observe the viewport element's size changes and keep the scrollbar thumb in sync. If ResizeObserver is undefined the component throws immediately during viewport setup rather than silently producing a broken scrollbar.
Solutions
- Add a ResizeObserver polyfill (e.g. resize-observer-polyfill) to the app entry point.
- Upgrade or configure the target browser/webview to one supporting ResizeObserver.
- In tests, stub global.ResizeObserver with a no-op class before mounting the component.
- Alternatively, patch Scrollbar.svelte to fall back to window resize + interval polling when the API is absent.
- Feature-detect before mounting Scrollbar and skip custom scrollbars on unsupported platforms.
Example fix
// before (test setup)
import { render } from "@testing-library/svelte";
// after
global.ResizeObserver = global.ResizeObserver || class { observe(){} unobserve(){} disconnect(){} };
import { render } from "@testing-library/svelte"; Defensive patterns
Strategy: fallback
Validate before calling
if (typeof window === "undefined" || typeof window.ResizeObserver === "undefined") {
// skip custom scrollbar or load polyfill first
import("resize-observer-polyfill").then((RO) => { (window as any).ResizeObserver = RO.default; });
} Type guard
function hasResizeObserver(w: Window): w is Window & { ResizeObserver: typeof ResizeObserver } {
return typeof (w as any).ResizeObserver === "function";
} Try / catch
try {
mountScrollbar(viewport);
} catch (err) {
if (err instanceof Error && err.message.includes("ResizeObserver")) {
mountNativeScrollbar(viewport); // browser default scrolling
} else throw err;
} Prevention
- Polyfill ResizeObserver at the app entry before any component mounts.
- Browserlist-test the oldest webview you ship.
- In jsdom tests, always stub global.ResizeObserver.
- Feature-detect modern DOM APIs in component setup and degrade instead of throwing.
When it happens
Trigger: The Scrollbar component is mounted in an environment without ResizeObserver: very old browsers (IE11, old Safari <13.4), non-browser jsdom-based test environments without the polyfill, or sandboxed webviews lacking the API.
Common situations: Unit tests rendering Svelte components in jsdom without a ResizeObserver polyfill; legacy embedded browsers; SSR/hydration setups where window is stubbed incompletely.
Understand the failure class
Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.
Related errors
- Clipboard access is unavailable.
- Expected to find content container
- No branch selected!
- No branch selected!
- No provider found for
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/30b69d97464666ca.
Report an issue: GitHub.
Appendix: source
Thrown at packages/ui/src/lib/components/scroll/Scrollbar.svelte:148
/////////////////////
// VIEWPORT EVENTS //
/////////////////////
function onViewportMouseEnter() {
if (!shouldShowOnHover) return;
visible = true;
}
function onViewportMouseLeave() {
if (!shouldShowOnHover) return;
visible = false;
}
function setupViewport(viewport: Element) {
if (!viewport) return;
if (typeof window.ResizeObserver === "undefined") {
throw new Error("window.ResizeObserver is missing.");
}
const observerSize = new ResizeObserver(() => {
updateTrack();
});
observerSize.observe(viewport);
const content = viewport.children.item(0);
if (!content) {
throw new Error("Expected to find content container");
}
// Sometimes the content size changes before the browser fires a
// scroll event, so we compensate here to avoid thumb jumpiness.
// However, if viewport.scrollTop has already been adjusted by
// another component (e.g. VirtualList's scroll compensation),
// we must use the actual value to avoid double-compensating.
const observerContentSize = new ResizeObserver(() => {View on GitHub (pinned to 58e5313667)