microsoft/playwright · error · Error

Cannot disconnect from this worker

Error message

Cannot disconnect from this worker

What it means

Thrown by Worker.disconnect when the Worker was constructed without an onDisconnect callback. The Worker object (for dedicated/service workers) only supports an explicit disconnect when the browser backend supplied a disconnect handler; otherwise the operation is unsupported for that worker type.

Source

Thrown at packages/playwright-core/src/server/page.ts:1043

  didClose() {
    if (this.existingExecutionContext)
      this.existingExecutionContext.contextDestroyed('Worker was closed');
    this.emit(Worker.Events.Close, this);
    this.openScope.close(new Error('Worker closed'));
  }

  async evaluateExpression(progress: Progress, expression: string, isFunction: boolean | undefined, arg: any): Promise<any> {
    return progress.race(js.evaluateExpression(await this._executionContextPromise, expression, { returnByValue: true, isFunction }, arg));
  }

  async evaluateExpressionHandle(progress: Progress, expression: string, isFunction: boolean | undefined, arg: any): Promise<any> {
    return progress.race(js.evaluateExpression(await this._executionContextPromise, expression, { returnByValue: false, isFunction }, arg));
  }

  async disconnect(progress: Progress, options: { reason?: string } = {}) {
    if (!this._onDisconnect)
      throw new Error('Cannot disconnect from this worker');
    this._closeReason = options.reason;
    await progress.race(this._onDisconnect());
  }
}

export class PageBinding extends DisposableObject {
  static kBindingName = '__playwright__binding__';

  static createInitScript(browserContext: BrowserContext): InitScript {
    return new InitScript(browserContext, `
      (() => {
        const module = {};
        ${rawBindingsControllerSource.source}
        const property = '${kBindingsControllerProperty}';
        if (!globalThis[property])
          globalThis[property] = new (module.exports.BindingsController())(globalThis, '${PageBinding.kBindingName}');
      })();
    `);

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Do not call disconnect on worker types that do not provide a disconnect handler; let the worker close naturally or close the page/context that owns it.
  2. If you maintain a custom backend, supply an onDisconnect callback when constructing the Worker so the operation is supported.
  3. Prefer detaching via page/context teardown instead of a per-worker disconnect.
Defensive patterns

Strategy: type-guard

Type guard

// Only call disconnect when the worker advertises support for it.
// In user code, prefer letting the owning page/context drive worker teardown.
function canDisconnect(worker) {
  // No public flag exists; default to NOT calling disconnect and rely on page/context close.
  return false;
}

Try / catch

try {
  await worker.disconnect();
} catch (e) {
  if (/Cannot disconnect from this worker/.test(e.message)) {
    // unsupported worker type: close the owning page/context instead
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the internal Worker disconnect path on a worker whose backend did not register a disconnect routine (e.g. a service worker or a worker type whose lifecycle is managed entirely by the browser). Triggered through low-level protocol use or an internal dispatcher, not a typical user API.

Common situations: Custom integrations that drive the server-side Worker API directly; calling disconnect on a worker created by a backend that does not support manual disconnect.

Related errors


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