{"record":{"id":"b0613e66bc1a33d8","repo":"Hmbown/CodeWhale","slug":"wtype-exited-result-code-result-stderr-trim-slice-0-200","errorCode":null,"errorMessage":"wtype exited ${result.code}: ${result.stderr.trim().slice(0, 200)}","messagePattern":"wtype exited (.+?): (.+?)","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/linux.mjs","lineNumber":201,"sourceCode":"    const key = xdotoolKey(rawKey);\n    const mods = parts.map((part) => aliases[part] ?? part);\n    if (!key || mods.some((mod) => !modifiers.has(mod))) throw new ExecError(`unknown key combination \"${text}\"`);\n    const modKey = aliases[rawKey] ?? rawKey;\n    const onlyModifier = modifiers.has(modKey);\n    const args = mods.flatMap((mod) => [\"-M\", mod]);\n    for (let i = 0; i < repeat; i++) {\n      args.push(onlyModifier ? \"-M\" : \"-P\", onlyModifier ? modKey : key);\n      if (holdMs) args.push(\"-s\", String(holdMs));\n      args.push(onlyModifier ? \"-m\" : \"-p\", onlyModifier ? modKey : key);\n    }\n    args.push(...mods.reverse().flatMap((mod) => [\"-m\", mod]));\n    // wtype owns a temporary Wayland keyboard; the compositor releases its\n    // keys on process exit, including cancellation. Keep the complete gesture\n    // in one process (https://github.com/atx/wtype#usage).\n    throwIfAborted();\n    const result = await run(\"wtype\", args, { timeoutMs: Math.max(10_000, holdMs + 8_000) });\n    throwIfAborted();\n    if (result.code !== 0) throw new ExecError(`wtype exited ${result.code}: ${result.stderr.trim().slice(0, 200)}`, result);\n  }\n\n  function assertNum(v, name) {\n    const n = Number(v);\n    if (!Number.isFinite(n)) throw new ExecError(`${name} must be a finite number`);\n    return n;\n  }\n\n  // ---------- AT-SPI tree ----------\n  const PYATSPI_APP = `def resolve_app(desktop, app_name):\n    apps = [desktop.getChildAtIndex(i) for i in range(desktop.childCount)]\n    if app_name:\n        matches = [app for app in apps if app and app_name.casefold() == (app.name or \"\").casefold()]\n        return matches[0] if len(matches) == 1 else None\n    return next((app for app in apps if app and app.childCount), None)\n`;\n  const PYATSPI_WALK = `import json, sys, pyatspi\n${PYATSPI_APP}","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/linux.mjs#L183-L219","documentation":"Thrown by the Wayland key path when the wtype subprocess exits non-zero. wtype synthesizes a temporary virtual Wayland keyboard and the code keeps the whole gesture (press, hold, release) in one process; the error surfaces wtype's own failure with its stderr (first 200 chars). Abort is checked before and after the run, so this is purely a wtype-level failure.","triggerScenarios":"wtype present and selected on Wayland, but the compositor rejects the virtual keyboard protocol (e.g. GNOME does not support zwp_virtual_keyboard_v1 for wtype), the gesture exceeds the timeout (max(10s, holdMs+8s)), or invalid key args were passed through.","commonSituations":"Running wtype on GNOME/Wayland compositors lacking the virtual-keyboard protocol; extremely long holdMs causing the computed timeout to fire and the process to be killed (non-zero exit); wtype built without protocol support.","solutions":["Read wtype's stderr in the message; 'compositor does not support' means you must switch input backends (ydotool + ydotoold).","Keep holdMs modest or raise the timeout path; the runtime is max(10000, holdMs+8000) ms.","Test wtype directly: `wtype -P ctrl -p ctrl` to confirm compositor support.","On GNOME, install ydotool and start ydotoold instead of relying on wtype.","Ensure the session probe identified Wayland correctly; under XWayland-only apps wtype gestures may not land."],"exampleFix":"// before\nawait waylandKey('ctrl+c', { holdMs: 60000 }); // exceeds timeout\n// after\nawait waylandKey('ctrl+c', { holdMs: 500 });","handlingStrategy":"try-catch","validationCode":"async function wtypeWorks() {\n  try { await run('wtype', ['-P', 'shift', '-p', 'shift'], { timeoutMs: 5000 }); return true; }\n  catch { return false; }\n}\nconst holdOk = (holdMs) => !holdMs || holdMs <= 60_000;","typeGuard":null,"tryCatchPattern":"try {\n  await waylandKey(combo, { holdMs });\n} catch (e) {\n  if (e instanceof ExecError && e.message.includes('wtype exited')) {\n    // fall back to ydotool (with ydotoold) — wtype unsupported on this compositor\n    await ydotoolKey(combo);\n  } else throw e;\n}","preventionTips":["Preflight `wtype` with a harmless press to confirm compositor support (fails on GNOME).","Keep holdMs small; runtime timeout is max(10s, holdMs+8s).","Have ydotool+ydotoold configured as the fallback input path.","Run inside the real Wayland session, not an XWayland-only context.","Match wtype version to compositor protocol support."],"tags":["subprocess","wtype","wayland","input"],"backgroundTag":"external-command-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}