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
- Run the tests under a virtual framebuffer: xvfb-run npm run test:e2e.
- Set the DISPLAY environment variable to an active X server (export DISPLAY=:0).
- Install and start Xvfb manually: Xvfb :99 -screen 0 1280x1024x24 & export DISPLAY=:99.
- 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
- Run Electron tests on Linux with: xvfb-run npm run test:e2e.
- In CI containers, install xvfb and start Xvfb, then export DISPLAY=:99.
- Ensure DISPLAY points at an active X server before launching Electron.
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
- fs is not available in the browser
- path is not available in the browser
- No devices found
- Cannot launch Firefox with relative home directory. Did you
- Launching more browsers is not allowed.
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/0c2d15f1f28cebcf.
Report an issue: GitHub.