grafana/k6 · error

getting layout metrics for screenshot: %w

Error message

getting layout metrics for screenshot: %w

What it means

getViewPortDimensions() calls Page.getLayoutMetrics to obtain the CSS visual viewport (scale, pageX, pageY) used to translate clip coordinates. The CDP command itself errored. (A nil cssVisualViewport is handled separately with a warn + defaults — this error is the command failing outright.)

Source

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

	// Save screenshot capture to file
	if path != "" {
		if err := s.persister.Persist(s.ctx, path, bytes.NewBuffer(buf)); err != nil {
			return nil, fmt.Errorf("persisting screenshot: %w", err)
		}
	}

	return buf, nil
}

func getViewPortDimensions(ctx context.Context, sess session, logger *log.Logger) (float64, float64, float64, error) {
	visualViewportScale := 1.0
	visualViewportPageX, visualViewportPageY := 0.0, 0.0

	// Add clip region
	//nolint:dogsled
	_, _, _, _, cssVisualViewport, _, err := cdppage.GetLayoutMetrics().Do(cdp.WithExecutor(ctx, sess))
	if err != nil {
		return 0, 0, 0, fmt.Errorf("getting layout metrics for screenshot: %w", err)
	}

	// we had a null pointer panic cases, when visualViewport is nil
	// instead of the erroring out, we fallback to defaults and still try to do a screenshot
	if cssVisualViewport != nil {
		visualViewportScale = cssVisualViewport.Scale
		visualViewportPageX = cssVisualViewport.PageX
		visualViewportPageY = cssVisualViewport.PageY
	} else {
		logger.Warnf(
			"Screenshotter::screenshot",
			"chrome browser returned nil on page.getLayoutMetrics, falling back to defaults for cssVisualViewport "+
				"(scale: %v, pageX: %v, pageY: %v)."+
				"This is non-standard behavior, if possible please report this issue (with a reproducible script) "+
				"to the https://github.com/grafana/k6/issues/new.",
			visualViewportScale, visualViewportPageX, visualViewportPageY,
		)
	}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Await full navigation before capturing: await page.goto(url); await page.waitForLoadState('load');
  2. Ensure the page stays open until screenshot() resolves.
  3. Retry once for transient 'Target closed'/'Session closed' messages.
  4. Stabilize the browser environment (memory limits, GPU flags) if chrome itself is dying.

Example fix

// before
page.goto(url); // unhandled promise
await page.screenshot({ path: 's.png' }); // getLayoutMetrics can race navigation

// after
await page.goto(url);
await page.screenshot({ path: 's.png' });
Defensive patterns

Strategy: retry

Validate before calling

await page.waitForLoadState('load'); // ensure no navigation in flight

Try / catch

try { await page.screenshot({ path: 's.png' }); }
catch (e) {
  if (String(e).includes('getting layout metrics')) { await sleep(500); await page.screenshot({ path: 's.png' }); }
  else throw e;
}

Prevention

When it happens

Trigger: Any screenshot with a viewport rect (page.screenshot of the viewport) while the target is closing, navigating, or the renderer is gone; CDP session cancelled by test shutdown or timeout.

Common situations: Screenshot racing page.goto()/reload()/close(); browser crashed under memory pressure; k6 scenario teardown cancelling the browser context mid-capture.

Related errors


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