garrytan/gstack · error · Error

viewport --scale is not supported in headed mode — scale is

Error message

viewport --scale is not supported in headed mode — scale is controlled by the real browser window.

What it means

Error "viewport --scale is not supported in headed mode — scale is controlled by the real browser window." thrown in garrytan/gstack.

Source

Thrown at browse/src/browser-manager.ts:1488

   * Change deviceScaleFactor + viewport size atomically.
   *
   * deviceScaleFactor is a context-level option, so Playwright requires a full context
   * recreation. This method validates the input, stores the new values, calls
   * recreateContext(), and rolls back the fields on failure so a bad call doesn't
   * leave the manager in an inconsistent state.
   *
   * Returns null on success, or an error string if the new context couldn't be built
   * (state may have been lost, per recreateContext's fallback behavior).
   */
  async setDeviceScaleFactor(scale: number, width: number, height: number): Promise<string | null> {
    if (!Number.isFinite(scale)) {
      throw new Error(`viewport --scale: value must be a finite number, got ${scale}`);
    }
    if (scale < 1 || scale > 3) {
      throw new Error(`viewport --scale: value must be between 1 and 3 (gstack policy cap), got ${scale}`);
    }
    if (this.connectionMode === 'headed') {
      throw new Error('viewport --scale is not supported in headed mode — scale is controlled by the real browser window.');
    }

    const prevScale = this.deviceScaleFactor;
    const prevViewport = { ...this.currentViewport };
    this.deviceScaleFactor = scale;
    this.currentViewport = { width, height };

    const err = await this.recreateContext();
    if (err !== null) {
      // recreateContext's fallback path built a blank context using the NEW scale +
      // viewport (the fields we just set). Rolling the fields back without a second
      // recreate would leave the live context at new-scale while state says old-scale.
      // Roll back fields FIRST, then force a second recreate against the old values
      // so live state matches tracked state.
      this.deviceScaleFactor = prevScale;
      this.currentViewport = prevViewport;
      const rollbackErr = await this.recreateContext();
      if (rollbackErr !== null) {

View on GitHub (pinned to 94993f7401)

When it happens

Trigger: Thrown at browse/src/browser-manager.ts:1488 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12). Data as JSON: /api/errors/4fcc557c31f5198f. Report an issue: GitHub.