{"record":{"id":"8050b57c708651ac","repo":"Hmbown/CodeWhale","slug":"display-enumeration-needs-xrandr-x11-or-swaymsg-hyprctl","errorCode":null,"errorMessage":"display enumeration needs xrandr (X11) or swaymsg/hyprctl (Wayland) — install one and retry","messagePattern":"display enumeration needs xrandr \\(X11\\) or swaymsg/hyprctl \\(Wayland\\) — install one and retry","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/linux.mjs","lineNumber":406,"sourceCode":"          displays.push({ index: i++, name: m[1], points: { x: Number(m[4]), y: Number(m[5]), w: Number(m[2]), h: Number(m[3]) }, pixels: { w: Number(m[2]), h: Number(m[3]) }, scale: 1, main: /primary/.test(m[0]) || i === 1 });\n        }\n        if (displays.length) return displays;\n      }\n      if (session === \"wayland\" && tools.swaymsg) {\n        const r = await run(\"swaymsg\", [\"-t\", \"get_outputs\", \"-r\"], { timeoutMs: 15_000 });\n        const outs = tryJson(r.stdout, []);\n        if (Array.isArray(outs) && outs.length) {\n          return outs.map((o, i) => ({ index: i + 1, name: o.name, points: { x: o.rect?.x, y: o.rect?.y, w: o.rect?.width, h: o.rect?.height }, pixels: { w: o.current_mode?.width, h: o.current_mode?.height }, scale: o.scale ?? 1, main: i === 0 }));\n        }\n      }\n      if (session === \"wayland\" && tools.hyprctl) {\n        const r = await run(\"hyprctl\", [\"-j\", \"monitors\"], { timeoutMs: 15_000 });\n        const ms = tryJson(r.stdout, []);\n        if (Array.isArray(ms) && ms.length) {\n          return ms.map((o, i) => ({ index: i + 1, name: o.name, points: { x: o.x, y: o.y, w: o.width, h: o.height }, pixels: { w: o.width, h: o.height }, scale: o.scale ?? 1, main: !!o.main || i === 0 }));\n        }\n      }\n      throw new ExecError(\"display enumeration needs xrandr (X11) or swaymsg/hyprctl (Wayland) — install one and retry\");\n    },\n    switch_display: async ({ index }) => ({ activeDisplay: index ?? 1, note: \"linux screenshots grab the compositor's virtual screen; per-display selection applies only where the shot tool supports it\" }),\n    list_apps: async () => {\n      await probeSession();\n      if (session === \"x11\" && tools.wmctrl) {\n        const r = await runOk(\"wmctrl\", [\"-lx\"], { timeoutMs: 15_000 });\n        const seen = new Map();\n        for (const line of r.stdout.split(\"\\n\")) {\n          const parts = line.split(/\\s+/);\n          const wmClass = parts[2];\n          if (wmClass) seen.set(wmClass, { name: wmClass.split(\".\")[0], wm_class: wmClass });\n        }\n        return { apps: [...seen.values()] };\n      }\n      if (session === \"wayland\" && (tools.swaymsg || tools.hyprctl)) {\n        const w = await this.list_windows();\n        const seen = new Map();\n        for (const win of w.windows) {","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/linux.mjs#L388-L424","documentation":"Thrown by the list_displays capability when no supported display-enumeration tool is available for the detected session: xrandr on X11, or swaymsg/hyprctl on Wayland. The backend probes session and tool availability first; if none of the expected binaries are present it fails with this explicit install hint rather than returning an empty list.","triggerScenarios":"Calling list_displays on a system where: X11 lacks xrandr (minimal X installs, some containers), or Wayland is neither sway (no swaymsg) nor hyprland (no hyprctl) — e.g. GNOME Wayland without any of the tools, or tools absent from PATH.","commonSituations":"Docker/CI images with bare Xvfb and no xrandr; GNOME/KDE Wayland sessions (this backend supports sway/hyprctl enumeration there, and neither tool exists); stripped-down embedded or minimal arch installs.","solutions":["On X11 install xrandr (x11-xserver-utils on Debian/Ubuntu) and ensure DISPLAY is set.","On sway install swaymsg (part of sway); on hyprland ensure hyprctl (part of hyprland) is in PATH.","On other Wayland compositors (GNOME/KDE), use an XWayland session or add a supported enumeration tool; this backend only enumerates via xrandr/swaymsg/hyprctl.","Verify which session was detected by checking for the binaries: `command -v xrandr swaymsg hyprctl`.","For headless CI, install xrandr alongside a virtual X server (xvfb + x11-xserver-utils)."],"exampleFix":"// before (Debian, X11 minimal)\n# xrandr: command not found\n// after\nsudo apt install x11-xserver-utils","handlingStrategy":"fallback","validationCode":"import { execFileSync } from 'child_process';\nconst has = (cmd) => { try { execFileSync('sh', ['-c', `command -v ${cmd}`], { stdio: 'ignore' }); return true; } catch { return false; } };\nfunction displayEnumAvailable(session) {\n  return session === 'x11' ? has('xrandr') : (has('swaymsg') || has('hyprctl'));\n}","typeGuard":null,"tryCatchPattern":"try {\n  const displays = await listDisplays();\n} catch (e) {\n  if (e instanceof ExecError && e.message.includes('display enumeration needs')) {\n    // degrade: return a single synthetic full-screen display\n    return [{ index: 1, name: 'screen', points: await virtualScreenBounds(), main: true }];\n  }\n  throw e;\n}","preventionTips":["Install x11-xserver-utils (xrandr) on X11 hosts, including CI images with Xvfb.","On sway/hyprland keep the compositor's CLI (swaymsg/hyprctl) on PATH.","For GNOME/KDE Wayland, plan for the limitation: this backend enumerates only via xrandr/swaymsg/hyprctl.","Check `command -v xrandr swaymsg hyprctl` in preflight and fail with install guidance early.","Keep the plugin's PATH aligned with the desktop session's environment."],"tags":["dependency","linux","displays","xrandr","wayland"],"backgroundTag":"missing-dependency","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T21:17:16.096Z"}