grafana/k6 · error

parsing browser.newPage options: %w

Error message

parsing browser.newPage options: %w

What it means

browser.newPage(opts) uses the same parseBrowserContextOptions pipeline as newContext: the passed value is exported onto a default-filled common.BrowserContextOptions struct, then proxy options are validated. Any export or validation failure is wrapped as 'parsing browser.newPage options'. newPage then creates an implicit context with those options.

Source

Thrown at internal/js/modules/k6/browser/browser/browser_mapping.go:82

		},
		"userAgent": func() (string, error) {
			b, err := browser()
			if err != nil {
				return "", err
			}
			return b.UserAgent(), nil
		},
		"version": func() (string, error) {
			b, err := browser()
			if err != nil {
				return "", err
			}
			return b.Version(), nil
		},
		"newPage": func(opts sobek.Value) (*sobek.Promise, error) {
			popts, err := parseBrowserContextOptions(vu.Runtime(), opts)
			if err != nil {
				return nil, fmt.Errorf("parsing browser.newPage options: %w", err)
			}
			return promise(vu, func() (any, error) {
				b, err := browser()
				if err != nil {
					return nil, err
				}
				page, err := b.NewPage(popts)
				if err != nil {
					return nil, err //nolint:wrapcheck
				}
				if err := initBrowserContext(b.Context(), vu.testRunID); err != nil {
					return nil, err
				}

				return mapPage(vu, page), nil
			}), nil
		},
	}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Use exactly the documented context option keys and types (viewport/screen objects, numeric deviceScaleFactor, boolean flags)
  2. If you only need a proxy, remember server is the one mandatory proxy field
  3. Inspect the wrapped cause after the colon - it names the field that failed to export

Example fix

// before: array viewport, string scale factor
const page = await browser.newPage({ viewport: [1280, 720], deviceScaleFactor: '2' });

// after: object viewport, numeric scale factor
const page = await browser.newPage({ viewport: { width: 1280, height: 720 }, deviceScaleFactor: 2 });
Defensive patterns

Strategy: type-guard

Validate before calling

// reuse the same shape check as newContext before calling newPage
function validContextOptions(o = {}) {
  const num = (v) => typeof v === 'number';
  if (o.viewport !== undefined && !(num(o.viewport.width) && num(o.viewport.height))) return false;
  if (o.deviceScaleFactor !== undefined && typeof o.deviceScaleFactor !== 'number') return false;
  if (o.proxy !== undefined && (typeof o.proxy.server !== 'string' || !o.proxy.server)) return false;
  return true;
}
if (!validContextOptions(opts)) throw new TypeError('bad browser page options');
const page = await browser.newPage(opts);

Type guard

interface Viewport { width: number; height: number }
interface PageOpts {
  viewport?: Viewport;
  deviceScaleFactor?: number;
  ignoreHTTPSErrors?: boolean;
  locale?: string;
  userAgent?: string;
  proxy?: { server: string; bypass?: string };
}
function isPageOpts(v: unknown): v is PageOpts {
  const o = v as PageOpts;
  return (
    v != null && typeof v === 'object' && !Array.isArray(v) &&
    (o.viewport == null || (typeof o.viewport.width === 'number' && typeof o.viewport.height === 'number')) &&
    (o.deviceScaleFactor == null || typeof o.deviceScaleFactor === 'number') &&
    (o.proxy == null || typeof o.proxy.server === 'string')
  );
}

Try / catch

try {
  page = await browser.newPage(opts);
} catch (e) {
  if (String(e).includes('parsing browser.newPage options')) {
    page = await browser.newPage(); // defaults, then set what you can via page APIs
  } else throw e;
}

Prevention

When it happens

Trigger: newPage({ viewport: [1280, 720] }) - array instead of {width, height}; newPage({ deviceScaleFactor: '2' }); newPage({ proxy: {} }) - empty proxy object fails 'proxy.server must be set'; any non-exportable value in the options object.

Common situations: Reusing a config object shared with other Playwright/Puppeteer calls whose field shapes differ; passing device descriptors with incompatible key names; env-var-driven booleans arriving as strings.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/869a77b52bf2f1b2. Report an issue: GitHub.