Hmbown/CodeWhale · error · ExecError
scroll on Wayland is not available in this build; use…
Error message
scroll on Wayland is not available in this build; use swipe-style drags or run an X11/XWayland window. (Roadmap: ydotool wheel events.)
What it means
On X11, scroll is implemented with xdotool mouse-button 4/5/6/7 clicks. On Wayland this build has no wheel-event synthesis wired (ydotool wheel support is a roadmap item), so the library fails honestly instead of faking a scroll. There is no Wayland implementation to fall back to.
Solutions
- Run the target app under XWayland and scroll inside that window, or force the app to X11 via env GDK_BACKEND=x11 / QT_QPA_PLATFORM=xcb.
- Use swipe-style pointer drags (move_to/left_click-drag sequences) to approximate scrolling.
- Install and wire ydotool with a running ydotoold if your build supports wheel events, or upgrade when the roadmap lands.
- Switch the session to X11 (login X11 session) if scrolling is essential.
Example fix
// before
await backend.scroll({ direction: 'down', amount: 5 }); // throws on Wayland
// after
if (sessionType !== 'x11') {
await backend.move_to({ x: cx, y: cy });
await dragSwipe({ dy: 120 }); // swipe-style drag instead
} else {
await backend.scroll({ direction: 'down', amount: 5 });
} Defensive patterns
Strategy: fallback
Validate before calling
const sess = await detectSession(); // 'x11' | 'wayland' if (sess !== 'x11' && action === 'scroll') useSwipeDragInstead();
Try / catch
try {
await backend.scroll({ direction, amount });
} catch (e) {
if (String(e.message).includes('scroll on Wayland')) {
await swipeDragFallback({ direction, amount });
return;
}
throw e;
} Prevention
- Detect session type (XDG_SESSION_TYPE) up front and branch input strategies
- Prefer XWayland for apps needing wheel events, or force GDK_BACKEND=x11
- Keep a drag-based scroll fallback implemented for Wayland targets
When it happens
Trigger: Calling scroll (any direction/amount) while the detected session is Wayland (sway, hyprland, GNOME-Wayland, KDE-Wayland); X11-only branch not taken because probeSession() reported non-x11.
Common situations: Automation scripts that work on an X11 desktop failing on the developer's Wayland laptop; CI containers running Wayland compositors; mixed fleets where the same action script runs on both session types.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- clipboard read failed
- cursor position needs an X11 session in this build
- linux backend needs " " for — install it and retry
- PRIMARY selection busy or unavailable
- could not parse xdotool getmouselocation output
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/41641188d9ec9936.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/linux.mjs:614
if (session === "x11") await xdotool(["mousedown", "1"]);
else await ydotool(["click", "0x40"]);
} catch (err) { await releaseMouse(); throw err; }
return { action_sent: true };
},
left_mouse_up: async () => {
if (!mouseHeld) throw Object.assign(new ExecError("no agent pointer press to release"), { code: "input_not_held" });
await releaseMouse();
return { action_sent: true };
},
scroll: async ({ target, direction = "down", amount = 3 }) => {
await inputMove(target.x, target.y);
if (session === "x11") {
const buttons = { down: 5, up: 4, right: 7, left: 6 };
await xdotool(["click", "--repeat", String(Math.max(1, Math.min(30, amount))), "--delay", "60", String(buttons[direction] ?? 5)]);
return { action_sent: true, direction, amount };
}
// Wayland: synthesize wheel via ydotool is not wired in this build — honest refusal.
throw new ExecError('scroll on Wayland is not available in this build; use swipe-style drags or run an X11/XWayland window. (Roadmap: ydotool wheel events.)');
},
type: async ({ text }) => {
if (!text) return { action_sent: false, note: "empty text" };
await probeSession();
if (session === "x11") {
// xdotool `type` remaps a spare keycode for characters absent from the
// current keymap. Two failure modes follow: a cased letter produces a
// single-symbol key whose XKB level 0 is the lowercase form (Ü → ü),
// and consecutive remaps inside one `type` call race the X server's
// keymap-change propagation, so non-ASCII chars intermittently drop or
// arrive mangled (héllo → hllo, 日本 → 本). Route every non-ASCII char
// through `key U<hex>` — one synchronous remap+press+restore per char —
// adding Shift only when the char is cased-uppercase, and batch ASCII
// runs through `type` as before.
let runText = "";
const chunks = [];
for (const ch of String(text)) {
if (ch.codePointAt(0) > 127) {View on GitHub (pinned to 73e0f67d83)