grafana/k6 · error

unpacking window size: %w

Error message

unpacking window size: %w

What it means

The in-page evaluation of window.innerWidth/window.innerHeight succeeded, but converting the returned value into the Size struct failed (JSON round-trip through helpers.go convert). The value came back in a shape that does not unmarshal into {width: float64, height: float64}.

Source

Thrown at internal/js/modules/k6/browser/common/screenshotter.go:142

	if viewportSize.Width != 0 || viewportSize.Height != 0 {
		return &viewportSize, &originalViewportSize, nil
	}

	opts := evalOptions{
		forceCallable: true,
		returnByValue: true,
	}
	result, err := p.frameManager.MainFrame().evaluate(s.ctx, mainWorld, opts, `
	() => (
		{ width: window.innerWidth, height: window.innerHeight }
	)`)
	if err != nil {
		return nil, nil, fmt.Errorf("getting viewport dimensions: %w", err)
	}

	var returnVal Size
	if err := convert(result, &returnVal); err != nil {
		return nil, nil, fmt.Errorf("unpacking window size: %w", err)
	}

	viewportSize.Width = returnVal.Width
	viewportSize.Height = returnVal.Height

	return &viewportSize, &originalViewportSize, nil
}

func (s *screenshotter) restoreViewport(p *Page, originalViewport *Size) error {
	if originalViewport != nil {
		return p.setViewportSize(originalViewport)
	}
	return p.resetViewport()
}

func (s *screenshotter) screenshot(
	sess session, doc, viewport *Rect, format ImageFormat, omitBackground bool, quality int64, path string,
) ([]byte, error) {

View on GitHub (pinned to 93accf6570)

Solutions

  1. Set an explicit viewport so this code path is never used: browser.newPage({ viewport: { width: 1280, height: 720 } }) or page.setViewportSize().
  2. Upgrade k6 and its bundled chromium — RemoteObject decoding for evaluated results has changed across versions.
  3. If a page script overrides window.innerWidth/innerHeight, neutralize it or screenshot a different page.
  4. Catch and fall back: skip size-dependent options (fullPage, clip) for that page.

Example fix

// before
const p = await browser.newContext().newPage(); // no viewport option -> 0x0 path possible
await p.screenshot({ path: 's.png' });

// after
const p = await browser.newContext({ viewport: { width: 1280, height: 720 } }).newPage();
await p.screenshot({ path: 's.png' });
Defensive patterns

Strategy: validation

Validate before calling

const w = await page.evaluate('window.innerWidth');
if (typeof w !== 'number' || !Number.isFinite(w)) throw new Error('viewport unreadable; set an explicit viewport');

Type guard

function isFiniteSize(v) {
  return v != null && typeof v === 'object'
    && Number.isFinite(Number(v.width)) && Number.isFinite(Number(v.height));
}

Try / catch

try { await page.screenshot({ path: 's.png' }); }
catch (e) { if (String(e).includes('unpacking window size')) { /* set viewport and retry */ } else throw e; }

Prevention

When it happens

Trigger: Only reachable from the same path as 'getting viewport dimensions' — a page with no emulated viewport (0x0) — where CDP returns a RemoteObject that deserializes into something other than a {width,height} number map (e.g. undefined, a string, or a sobek value that does not marshal cleanly).

Common situations: Rare; seen with non-standard documents (about:blank races, pages replacing window properties, aggressive anti-automation scripts tampering with window.innerWidth) and with browser/k6 version mismatches in how RemoteObjects are decoded.

Related errors


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