microsoft/playwright · error · Error

Unable to open X display! ================================ M

Error message

Unable to open X display!
================================
Most likely this is because there is no X server available.
Use 'xvfb-run' on Linux to launch your tests with an emulated display server.
For example: 'xvfb-run npm run test:e2e'
================================
${progress.metadata.log}

What it means

On Linux, Electron (a GUI app) requires an X display. The launched process streams its stderr; waitForLine watches for 'Unable to open X display' and, when it appears, throws a formatted error. This fires when there is no X server (headless server, plain SSH) and no virtual display is configured.

Source

Thrown at packages/playwright-core/src/server/electron/electron.ts:260

      log: (message: string) => {
        progress.log(message);
        browserLogsCollector.log(message);
      },
      shell,
      stdio: 'pipe',
      cwd: options.cwd,
      tempDirectories,
      attemptToGracefullyClose: () => app!.close(nullProgress),
      handleSIGINT: true,
      handleSIGTERM: true,
      handleSIGHUP: true,
      onExit: () => app?.emit(ElectronApplication.Events.Close),
    }));

    // All waitForLines must be started immediately.
    // Otherwise the lines might come before we are ready.
    const waitForXserverError = waitForLine(progress, launchedProcess, /Unable to open X display/).then(() => {
      throw new Error([
        'Unable to open X display!',
        `================================`,
        'Most likely this is because there is no X server available.',
        "Use 'xvfb-run' on Linux to launch your tests with an emulated display server.",
        "For example: 'xvfb-run npm run test:e2e'",
        `================================`,
        progress.metadata.log
      ].join('\n'));
    });
    const nodeMatchPromise = waitForLine(progress, launchedProcess, /^Debugger listening on (ws:\/\/.*)$/);
    const chromeMatchPromise = waitForLine(progress, launchedProcess, /^DevTools listening on (ws:\/\/.*)$/);
    const debuggerDisconnectPromise = waitForLine(progress, launchedProcess, /Waiting for the debugger to disconnect\.\.\./);

    try {
      const nodeMatch = await nodeMatchPromise;
      const nodeTransport = await WebSocketTransport.connect(progress, nodeMatch[1]);
      const nodeConnection = new CRConnection(this, nodeTransport, helper.debugProtocolLogger(), browserLogsCollector);
      // Immediately release exiting process under debug.

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Run the tests under a virtual framebuffer: xvfb-run npm run test:e2e.
  2. Set the DISPLAY environment variable to an active X server (export DISPLAY=:0).
  3. Install and start Xvfb manually: Xvfb :99 -screen 0 1280x1024x24 & export DISPLAY=:99.
  4. Run on a host/CI image that ships a display or pre-configured Xvfb.

Example fix

# before
npm run test:e2e   # electron.launch() throws 'Unable to open X display'
# after
xvfb-run npm run test:e2e
Defensive patterns

Strategy: fallback

Validate before calling

// Detect a headless Linux environment and require a virtual display.
if (process.platform === 'linux' && !process.env.DISPLAY) {
  throw new Error('No DISPLAY set — run under xvfb-run or start Xvfb');
}

Prevention

When it happens

Trigger: Running electron.launch() on a headless Linux box with no DISPLAY and no Xvfb; CI container without an X server; SSH session without X forwarding.

Common situations: Linux CI (Docker/Ubuntu runner) running Electron tests directly instead of under xvfb; deploying Electron automation to a server without a desktop environment.

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/0c2d15f1f28cebcf. Report an issue: GitHub.