{"record":{"id":"4e93682db4d454cf","repo":"Hmbown/CodeWhale","slug":"no-x11-display-or-wayland-wayland-display-session-visible-to","errorCode":null,"errorMessage":"no X11 ($DISPLAY) or Wayland ($WAYLAND_DISPLAY) session visible to this process","messagePattern":"no X11 \\(\\$DISPLAY\\) or Wayland \\(\\$WAYLAND_DISPLAY\\) session visible to this process","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/linux.mjs","lineNumber":124,"sourceCode":"    }\n    tools.pyatspi = tools.python3 && (await run(\"python3\", [\"-c\", \"import pyatspi\"], { timeoutMs: 10_000 })).code === 0;\n    throwIfAborted();\n    probed = true;\n    return session;\n  }\n\n  function need(tool, purpose) {\n    if (!tools[tool]) throw new ExecError(`linux backend needs \"${tool}\" for ${purpose} — install it and retry`);\n  }\n\n  async function shotTool() {\n    if (session === \"wayland\") { need(\"grim\", \"screenshots on Wayland\"); return { cmd: \"grim\", base: [] }; }\n    if (session === \"x11\") {\n      if (tools.scrot) return { cmd: \"scrot\", base: [\"-z\"] };\n      need(\"import\", \"screenshots on X11 (imagemagick)\");\n      return { cmd: \"import\", base: [\"-window\", \"root\"] };\n    }\n    throw new ExecError(\"no X11 ($DISPLAY) or Wayland ($WAYLAND_DISPLAY) session visible to this process\");\n  }\n\n  /** Capture a PNG to `file`, optionally cropped to region [x,y,w,h] points. */\n  async function takeShot(file, region) {\n    outputPath(file);\n    const { cmd, base } = await shotTool();\n    let args = [...base];\n    if (cmd === \"grim\") {\n      if (region) args.push(\"-g\", `${Math.round(region[0])},${Math.round(region[1])} ${Math.round(region[2])}x${Math.round(region[3])}`);\n      args.push(file);\n    } else if (cmd === \"scrot\") {\n      if (region) args.push(\"-a\", `${Math.round(region[0])},${Math.round(region[1])},${Math.round(region[2])},${Math.round(region[3])}`);\n      args.push(file);\n    } else {\n      if (region) args.push(\"-crop\", `${Math.round(region[2])}x${Math.round(region[3])}+${Math.round(region[0])}+${Math.round(region[1])}`);\n      args.push(file);\n    }\n    const r = await run(cmd, args, { timeoutMs: 10_000 });","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/linux.mjs#L106-L142","documentation":"`shotTool` picks a screenshot tool based on the detected session (\"wayland\" or \"x11\"). If neither $WAYLAND_DISPLAY nor $DISPLAY is set/visible to this process, no screenshot mechanism can work, so it throws instead of guessing. This is an environment-detection failure, not a tool failure.","triggerScenarios":"Calling any screenshot/capture API on the Linux backend when the process has no DISPLAY or WAYLAND_DISPLAY environment variable (e.g. running via SSH without X forwarding, a systemd service, a cron job, or a container without the socket mounted) (backends/linux.mjs:124).","commonSituations":"Running the agent from a headless shell/CI; SSH session without `ssh -X`; Wayland user session but process launched before the session env is imported; container without passing through the display socket and env.","solutions":["Run the backend from within a graphical session shell so DISPLAY or WAYLAND_DISPLAY is set.","For SSH, use `ssh -X` or run the automation on the machine with the GUI session.","In containers/systemd, pass through the display env and socket (e.g. -e WAYLAND_DISPLAY -v $XDG_RUNTIME_DIR:/tmp/xdg).","Verify with `echo $DISPLAY $WAYLAND_DISPLAY` in the same environment the backend runs in."],"exampleFix":"// before\n// CI container: neither DISPLAY nor WAYLAND_DISPLAY set -> throws\n// after\n// docker run -e WAYLAND_DISPLAY=$WAYLAND_DISPLAY -v $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY:/tmp/$WAYLAND_DISPLAY ...\nawait backend.screenshot({ file: \"/tmp/s.png\" });","handlingStrategy":"validation","validationCode":"if (!process.env.DISPLAY && !process.env.WAYLAND_DISPLAY)\n  throw new Error(\"no graphical session: set DISPLAY or WAYLAND_DISPLAY\");","typeGuard":"const hasGraphicalSession = Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);","tryCatchPattern":"try { await backend.screenshot({ file }); }\ncatch (e) {\n  if (String(e.message).includes(\"no X11\") && String(e.message).includes(\"Wayland\"))\n    throw new Error(\"Run inside a graphical session or export DISPLAY/WAYLAND_DISPLAY\");\n  throw e;\n}","preventionTips":["Launch automation from within the GUI session","Use ssh -X or forward the Wayland socket for remote runs","Pass display env/sockets into containers and services","Check DISPLAY/WAYLAND_DISPLAY in startup diagnostics"],"tags":["display","environment","wayland","x11","headless"],"backgroundTag":"missing-env-var","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"}