microsoft/playwright · error
Screencast is already started
Error message
Screencast is already started
What it means
A guard error thrown at the top of Screencast.start() when the client-side _started flag is already true. Each Page owns a single Screencast instance, so calling start() twice without an intervening stop() (or disposing the DisposableStub returned by the first start) hits this sentinel. It is a local state check, not a browser-side failure; only one screencast session per page is allowed.
Solutions
- Call stop() (or dispose the DisposableStub returned by the first start()) before calling start() again.
- Reuse the DisposableStub from the initial start() call instead of starting a second screencast.
- Track whether the screencast is active in your code and skip the second start() call.
- If a prior start() failed mid-way, ensure stop() ran so the _started flag is reset.
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at packages/playwright-core/src/client/screencast.ts:44 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of microsoft/playwright@f1d33b5029 (2026-09-21).
Data as JSON: /api/errors/3007c1845e23a6d9.
Report an issue: GitHub.
Appendix: source
Thrown at packages/playwright-core/src/client/screencast.ts:44
private _started = false;
private _savePath: string | undefined;
private _onFrame: ((frame: { data: Buffer, timestamp: number, viewportWidth: number, viewportHeight: number }) => Promise<any>) | null = null;
private _artifact: Artifact | undefined;
constructor(page: Page) {
this._page = page;
this._page._channel.on('screencastFrame', async ({ frameId, data, timestamp, viewportWidth, viewportHeight }) => {
try {
await this._onFrame?.({ data, timestamp, viewportWidth, viewportHeight });
} finally {
await this._page._channel.screencastFrameAck({ frameId }, kNoTimeout).catch(() => {});
}
});
}
async start(options: { onFrame?: (frame: { data: Buffer, timestamp: number, viewportWidth: number, viewportHeight: number }) => Promise<any>|any, path?: string, size?: { width: number, height: number }, quality?: number, fps?: number } = {}): Promise<DisposableStub> {
if (this._started)
throw new Error('Screencast is already started');
this._started = true;
if (options.onFrame)
this._onFrame = options.onFrame;
const result = await this._page._channel.screencastStart({
size: options.size,
quality: options.quality,
fps: options.fps,
sendFrames: !!options.onFrame,
record: !!options.path,
}, kNoTimeout);
if (result.artifact) {
this._artifact = Artifact.from(result.artifact);
this._savePath = options.path;
}
return new DisposableStub(() => this.stop());
}
async stop(): Promise<void> {View on GitHub (pinned to f1d33b5029)