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

  1. Call stop() (or dispose the DisposableStub returned by the first start()) before calling start() again.
  2. Reuse the DisposableStub from the initial start() call instead of starting a second screencast.
  3. Track whether the screencast is active in your code and skip the second start() call.
  4. 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)