Hmbown/CodeWhale · error · ExecError
wtype failed
Error message
wtype failed: ${r.stderr.slice(0, 200)} What it means
On Wayland, typing is delegated to the wtype utility; this error is thrown when wtype exits non-zero and includes its first 200 bytes of stderr. It means wtype itself failed — not that the backend refused — usually due to missing input-method/virtual-keyboard protocol support or a bad character for the current keymap.
Solutions
- Read the stderr excerpt in the message for the exact wtype complaint.
- Test manually: wtype -- 'hello' in a terminal on the same session to reproduce.
- Ensure the compositor allows the virtual-keyboard protocol and the client can access the Wayland socket (WAYLAND_DISPLAY set, not sandboxed).
- Switch keyboard layout or strip unsupported characters; alternatively run the app under XWayland and use the xdotool typing path.
Example fix
// before
await backend.type({ text: 'naïve café' }); // fails under restricted keymap
// after
const ascii = text.normalize('NFD').replace(/[^\x20-\x7E]/g, '');
await backend.type({ text: ascii }); // or fix wtype/Wayland env first Defensive patterns
Strategy: try-catch
Validate before calling
const chk = spawnSync('wtype', ['--', ''], { env: process.env });
if (chk.error || chk.status !== 0) throw new Error('wtype unavailable or blocked: ' + chk.stderr); Try / catch
try {
await backend.type({ text });
} catch (e) {
if (String(e.message).startsWith('wtype failed:')) {
// sanitize text or fall back to clipboard paste
await setClipboard(text);
await backend.key({ text: 'ctrl+v' });
return;
}
throw e;
} Prevention
- Test wtype from a terminal in the same session before automating
- Avoid characters unsupported by the active keymap, or normalize text first
- Don't run automation inside sandboxes that block Wayland virtual-keyboard protocol
When it happens
Trigger: wtype not granted the virtual-keyboard protocol (compositor rejects: sway needs no config but some compositors restrict it; hyprland fine, but sandboxed/flatpak contexts blocked); typing characters not representable in the active keymap/layout; wtype binary present but the session lacks zwp_virtual_keyboard_manager; running under a compositor without virtual keyboard support.
Common situations: Flatpak/sandboxed environments where Wayland protocol sockets are restricted; non-US keymaps choking on specific Unicode; headless Wayland (cage, gamescope) without keyboard protocol; wtype installed but ydotoold/uinput permissions missing — though wtype uses libxkbcommon + virtual keyboard directly.
Related errors
- clipboard read failed
- exited
- cursor position needs an X11 session in this build
- display enumeration needs xrandr (X11) or swaymsg/hyprctl…
- linux backend needs " " for — install it and retry
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/43d0d3ac7a17524d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/linux.mjs:659
if (chunk.codePointAt(0) > 127) {
const hex = chunk.codePointAt(0).toString(16).toUpperCase().padStart(4, "0");
const shift = chunk !== chunk.toLowerCase() ? "shift+" : "";
await xdotool(["key", `${shift}U${hex}`]);
// Each temp remap restores the keymap as soon as the event is
// queued; a lagging app can then read the press against the
// restored map and drop it. A short settle narrows that window.
// Under heavy host saturation XTEST drops remain possible — that
// residual is documented in the suite's known_limitations.
await new Promise((r) => setTimeout(r, 30));
} else {
await xdotool(["type", "--delay", "12", "--", chunk]);
}
}
return { action_sent: true, chars: text.length };
}
need("wtype", "typing on Wayland");
const r = await run("wtype", ["--", String(text)], { timeoutMs: 15_000 });
if (r.code !== 0) throw new ExecError(`wtype failed: ${r.stderr.slice(0, 200)}`, r);
return { action_sent: true, chars: text.length };
},
key: async ({ text, repeat = 1 }) => {
await probeSession();
const k = xdotoolKey(text);
const n = Math.max(1, Math.min(100, Number(repeat) || 1));
if (session === "x11") {
throwIfAborted();
heldKeys.add(k);
try {
await xdotool(["key", "--repeat", String(n), "--delay", "60", k]);
heldKeys.delete(k);
} finally { await releaseKey(k); }
} else await waylandKey(text, { repeat: n });
return { action_sent: true, key: k };
},
hold_key: async ({ text, duration }) => {
requireInputOwner();View on GitHub (pinned to 73e0f67d83)