{"record":{"id":"e409be91e21649af","repo":"Hmbown/CodeWhale","slug":"at-spi-walk-failed-is-python3-pyatspi-installed-and-the","errorCode":null,"errorMessage":"AT-SPI walk failed — is python3-pyatspi installed and the desktop running an accessibility bus (AT_SPI_BUS)?","messagePattern":"AT-SPI walk failed — is python3-pyatspi installed and the desktop running an accessibility bus \\(AT_SPI_BUS\\)\\?","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/linux.mjs","lineNumber":492,"sourceCode":"          }\n        } catch { /* no session/tools — the launch itself is still fine */ }\n      }\n      spawnDetached(target, urlArg ? [urlArg] : [], \"\", true);\n      await new Promise((r) => setTimeout(r, 500));\n      let focusRestored = false;\n      if (prevWindow) {\n        try {\n          focusRestored = (await run(\"xdotool\", [\"windowactivate\", prevWindow], { timeoutMs: 3_000 })).code === 0;\n        } catch { /* best-effort */ }\n      }\n      return { launched: true, name: target, url: urlArg ?? null, activate: activate === true, ...(activate === true ? {} : { focus_restored: focusRestored }) };\n    },\n    get_app_state: async ({ app_ref, window_id } = {}) => {\n      const name = appName(app_ref);\n      if (window_id !== undefined) throw Object.assign(new ExecError(\"Linux app-state window_id selection is unavailable\"), { code: \"unsupported_selector\" });\n      const t = await run(\"python3\", [\"-c\", PYATSPI_WALK, name, \"10\", \"500\"], { timeoutMs: 45_000 }).then((r) =>\n        tryJson((r.stdout.trim().split(\"\\n\").pop() ?? \"\"), null));\n      if (!t) throw new ExecError(\"AT-SPI walk failed — is python3-pyatspi installed and the desktop running an accessibility bus (AT_SPI_BUS)?\");\n      if (!t.found) throw new ExecError(\"application not found or name is ambiguous in the AT-SPI tree — use a unique exact app_ref.name\");\n      return t;\n    },\n    screenshot: async (args = {}) => {\n      rejectWindowSelectors(args);\n      const { display, region, path: outPath } = args;\n      if (outPath != null) outputPath(outPath);\n      await probeSession();\n      const dir = recordingsDir();\n      fs.mkdirSync(dir, { recursive: true });\n      const file = outPath || path.join(dir, `shot-${new Date().toISOString().replace(/[:.]/g, \"-\")}-${crypto.randomBytes(3).toString(\"hex\")}.png`);\n      await takeShot(file, region);\n      const dims = pngSize(file);\n      lastRaster = {\n        file,\n        bytes: fs.statSync(file).size,\n        // Region rasters describe the region; full shots get geometry from the\n        // PNG itself (Linux shots are always scale 1: points == pixels).","sourceCodeStart":474,"sourceCodeEnd":510,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/linux.mjs#L474-L510","documentation":"get_app_state reads UI state by running a python3 pyatspi script over the AT-SPI accessibility tree. The library throws this when the python helper produced no parseable JSON — typically because python3-pyatspi is not installed or the session has no AT-SPI accessibility bus running.","triggerScenarios":"python3 missing or python3-pyatspi not installed; desktop without AT_SPI_BUS (no accessibility enabled in GNOME/KDE settings); the 45s timeout expiring so no output is emitted; the script crashing and its stderr being the last line, which fails JSON parsing.","commonSituations":"Minimal/tiling WM setups (sway, i3, hyprland) where accessibility support is not installed; headless CI machines; containers without the at-spi dbus; users who disabled assistive technologies.","solutions":["Install the accessibility stack: sudo apt install python3-pyatspi (or distro equivalent).","Enable accessibility: ensure the AT-SPI bus is running (e.g. org.a11y.Bus enabled; on GNOME set org.gnome.desktop.interface toolkit-accessibility true).","Verify manually: python3 -c 'import pyatspi' should succeed, and check $AT_SPI_BUS or the session's a11y bus.","Re-run get_app_state after confirming a desktop session is active (not a bare headless shell)."],"exampleFix":"// before\nconst state = await backend.get_app_state({ app_ref: { name: 'Firefox' } }); // throws without pyatspi\n// after\nconst { code } = await run('python3', ['-c', 'import pyatspi']);\nif (code !== 0) throw new Error('install python3-pyatspi and enable the a11y bus first');\nconst state = await backend.get_app_state({ app_ref: { name: 'Firefox' } });","handlingStrategy":"fallback","validationCode":"const ok = spawnSync('python3', ['-c', 'import pyatspi']).status === 0;\nif (!ok) throw new Error('python3-pyatspi missing / a11y bus unavailable');","typeGuard":null,"tryCatchPattern":"try {\n  return await backend.get_app_state({ app_ref });\n} catch (e) {\n  if (String(e.message).includes('AT-SPI walk failed')) return null; // degrade gracefully\n  throw e;\n}","preventionTips":["Provision python3-pyatspi in every environment the automation runs in","Enable the accessibility bus in desktop settings before running UI automation","Health-check the a11y stack at startup, not at first use"],"tags":["linux","accessibility","atspi","missing-dependency","environment"],"backgroundTag":"missing-dependency","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}