microsoft/playwright · error · Error
Pipe has been closed
Error message
Pipe has been closed
What it means
Thrown by PipeTransport.send when a protocol message is written after the pipe has been marked closed. PipeTransport is the stdio-based channel between Playwright and a browser process launched with a pipe; once the read side emits 'close' (browser exited/crashed), any further send is rejected.
Source
Thrown at packages/playwright-core/src/server/pipeTransport.ts:59
});
pipeRead.on('error', e => debugLogger.log('error', e));
pipeWrite.on('error', e => debugLogger.log('error', e));
this.onmessage = undefined;
}
get onclose() {
return this._onclose;
}
set onclose(onclose: undefined | ((reason?: string) => void)) {
this._onclose = onclose;
if (onclose && !this._pipeRead.readable)
onclose();
}
send(message: ProtocolRequest) {
if (this._closed)
throw new Error('Pipe has been closed');
this._pipeWrite.write(JSON.stringify(message));
this._pipeWrite.write('\0');
}
close() {
throw new Error('unimplemented');
}
_dispatch(buffer: Buffer) {
let end = buffer.indexOf('\0');
if (end === -1) {
this._pendingBuffers.push(buffer);
return;
}
this._pendingBuffers.push(buffer.slice(0, end));
const message = Buffer.concat(this._pendingBuffers).toString();
this._waitForNextTask(() => {
if (this.onmessage)View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Treat browser process exit as terminal: stop issuing commands once the browser/Page close event has fired.
- Ensure no fire-and-forget commands outlive the browser; await all operations before calling browser.close().
- Investigate the actual browser crash (check stderr/stdout, system logs, dmesg for OOM) if the close was unexpected.
Example fix
// before browser.close(); // browser exits await page.title(); // PipeTransport.send -> Pipe has been closed // after const title = await page.title(); await browser.close();
Defensive patterns
Strategy: try-catch
Validate before calling
if (browser.isConnected() === false) throw new Error('browser not connected'); Try / catch
try {
await page.title();
} catch (e) {
if (/Pipe has been closed/.test(e.message)) {
// browser process is gone; recreate the browser rather than retrying commands
throw new Error('Browser process exited unexpectedly');
}
throw e;
} Prevention
- Check browser.isConnected()/page.isClosed() before issuing commands when lifecycle is uncertain.
- Await all operations before calling browser.close().
- Investigate unexpected browser exits (OOM, crashes) via stderr and system logs.
When it happens
Trigger: The browser process exited (crash, OOM, or explicit kill) while Playwright still had pending protocol requests; an operation is attempted on a Browser/Page after browser.close() or after the process died; a background task sends a command after teardown.
Common situations: Browser crashed due to resource exhaustion; test teardown raced with an in-flight command; the process was killed externally (CI timeout, container OOM); launching with pipe channel on an unstable environment.
Related errors
- Cannot find command to respond: ${id}
- Cannot find object to "${method}": ${guid}
- Unknown new child: ${params.guid}
- Cannot find parent object ${parentGuid} to create ${guid}
- ${path}: no object with guid ${guid}
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/69f88adbc0b69a57.
Report an issue: GitHub.