microsoft/playwright · error · Error

"deviceScaleFactor" option is not supported with null…

Error message

"deviceScaleFactor" option is not supported with null "viewport"

What it means

`validateBrowserContextOptions` rejects combining `noDefaultViewport: true` (null viewport) with `deviceScaleFactor`, because without a viewport Playwright cannot apply a device scale factor — the browser window itself is the viewport.

Solutions

  1. Remove `deviceScaleFactor` when using `noDefaultViewport` / `viewport: null`
  2. Or set an explicit viewport so deviceScaleFactor applies

Example fix

// before
await browser.newContext({ viewport: null, deviceScaleFactor: 2 });

// after
await browser.newContext({ viewport: null });
Defensive patterns

Strategy: validation

Validate before calling

function validateContextOpts(o: { viewport?: null; noDefaultViewport?: boolean; deviceScaleFactor?: number; isMobile?: boolean }) {
  const nullVp = o.viewport === null || !!o.noDefaultViewport;
  if (nullVp && o.deviceScaleFactor !== undefined)
    throw new Error('deviceScaleFactor requires a viewport (remove noDefaultViewport).');
  if (nullVp && !!o.isMobile)
    throw new Error('isMobile requires a viewport (remove noDefaultViewport).');
}

Prevention

When it happens

Trigger: `browser.newContext({ noDefaultViewport: true, deviceScaleFactor: 2 })` or `{ viewport: null, deviceScaleFactor: 2 }`.

Common situations: Switching to headless/windowed mode with `viewport: null` while keeping deviceScaleFactor from a previous config; desktop-automation setups reusing mobile configs.

Related errors


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

Appendix: source

Thrown at packages/playwright-core/src/server/browserContext.ts:772

    await Promise.all(this.pages().map(page => page.safeNonStallingEvaluateInAllFrames(expression, world, options)));
  }

  addRouteInFlight(route: network.Route) {
    this._routesInFlight.add(route);
  }

  removeRouteInFlight(route: network.Route) {
    this._routesInFlight.delete(route);
  }

  async notifyRoutesInFlightAboutRemovedHandler(handler: network.RouteHandler): Promise<void> {
    await Promise.all([...this._routesInFlight].map(route => route.removeHandler(handler)));
  }
}

export function validateBrowserContextOptions(options: types.BrowserContextOptions, browserOptions: BrowserOptions) {
  if (options.noDefaultViewport && options.deviceScaleFactor !== undefined)
    throw new Error(`"deviceScaleFactor" option is not supported with null "viewport"`);
  if (options.noDefaultViewport && !!options.isMobile)
    throw new Error(`"isMobile" option is not supported with null "viewport"`);
  if (options.acceptDownloads === undefined && browserOptions.name !== 'electron')
    options.acceptDownloads = 'accept';
  // Electron requires explicit acceptDownloads: true since we wait for
  // https://github.com/electron/electron/pull/41718 to be widely shipped.
  // In 6-12 months, we can remove this check.
  else if (options.acceptDownloads === undefined && browserOptions.name === 'electron')
    options.acceptDownloads = 'internal-browser-default';
  if (!options.viewport && !options.noDefaultViewport)
    options.viewport = { width: 1280, height: 720 };
  if (options.proxy)
    options.proxy = normalizeProxySettings(options.proxy);
  if (options.recordVideo?.fps !== undefined && options.recordVideo.fps <= 0)
    throw new Error(`"recordVideo.fps" must be a positive number, got ${options.recordVideo.fps}`);
  verifyGeolocation(options.geolocation);
}

View on GitHub (pinned to f1d33b5029)