{"record":{"id":"4fcc557c31f5198f","repo":"garrytan/gstack","slug":"viewport-scale-is-not-supported-in-headed-mode","errorCode":null,"errorMessage":"viewport --scale is not supported in headed mode — scale is controlled by the real browser window.","messagePattern":"viewport --scale is not supported in headed mode — scale is controlled by the real browser window\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/browser-manager.ts","lineNumber":1488,"sourceCode":"   * Change deviceScaleFactor + viewport size atomically.\n   *\n   * deviceScaleFactor is a context-level option, so Playwright requires a full context\n   * recreation. This method validates the input, stores the new values, calls\n   * recreateContext(), and rolls back the fields on failure so a bad call doesn't\n   * leave the manager in an inconsistent state.\n   *\n   * Returns null on success, or an error string if the new context couldn't be built\n   * (state may have been lost, per recreateContext's fallback behavior).\n   */\n  async setDeviceScaleFactor(scale: number, width: number, height: number): Promise<string | null> {\n    if (!Number.isFinite(scale)) {\n      throw new Error(`viewport --scale: value must be a finite number, got ${scale}`);\n    }\n    if (scale < 1 || scale > 3) {\n      throw new Error(`viewport --scale: value must be between 1 and 3 (gstack policy cap), got ${scale}`);\n    }\n    if (this.connectionMode === 'headed') {\n      throw new Error('viewport --scale is not supported in headed mode — scale is controlled by the real browser window.');\n    }\n\n    const prevScale = this.deviceScaleFactor;\n    const prevViewport = { ...this.currentViewport };\n    this.deviceScaleFactor = scale;\n    this.currentViewport = { width, height };\n\n    const err = await this.recreateContext();\n    if (err !== null) {\n      // recreateContext's fallback path built a blank context using the NEW scale +\n      // viewport (the fields we just set). Rolling the fields back without a second\n      // recreate would leave the live context at new-scale while state says old-scale.\n      // Roll back fields FIRST, then force a second recreate against the old values\n      // so live state matches tracked state.\n      this.deviceScaleFactor = prevScale;\n      this.currentViewport = prevViewport;\n      const rollbackErr = await this.recreateContext();\n      if (rollbackErr !== null) {","sourceCodeStart":1470,"sourceCodeEnd":1506,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/browser-manager.ts#L1470-L1506","documentation":"Error \"viewport --scale is not supported in headed mode — scale is controlled by the real browser window.\" thrown in garrytan/gstack.","triggerScenarios":"Thrown at browse/src/browser-manager.ts:1488 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":[],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}