{"record":{"id":"17a1a89ef4ea3952","repo":"grafana/k6","slug":"clip-area-is-either-empty-or-outside-the-viewport","errorCode":null,"errorMessage":"clip area is either empty or outside the viewport","messagePattern":"clip area is either empty or outside the viewport","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/screenshotter.go","lineNumber":453,"sourceCode":"}\n\nfunc (s *screenshotter) trimClipToSize(clip *Rect, size *Size) (*Rect, error) {\n\tp1 := Position{\n\t\tX: math.Max(0, math.Min(clip.X, size.Width)),\n\t\tY: math.Max(0, math.Min(clip.Y, size.Height)),\n\t}\n\tp2 := Position{\n\t\tX: math.Max(0, math.Min(clip.X+clip.Width, size.Width)),\n\t\tY: math.Max(0, math.Min(clip.Y+clip.Height, size.Height)),\n\t}\n\tresult := Rect{\n\t\tX:      p1.X,\n\t\tY:      p1.Y,\n\t\tWidth:  p2.X - p1.X,\n\t\tHeight: p2.Y - p1.Y,\n\t}\n\tif result.Width == 0 || result.Height == 0 {\n\t\treturn nil, errors.New(\"clip area is either empty or outside the viewport\")\n\t}\n\treturn &result, nil\n}\n","sourceCodeStart":435,"sourceCodeEnd":457,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/screenshotter.go#L435-L457","documentation":"The screenshotter intersects the requested clip rectangle with the current viewport (screenshotter.go:443-456). If the intersection has zero width or height — the clip is empty or lies entirely outside the viewport — the screenshot is refused with 'clip area is either empty or outside the viewport'.","triggerScenarios":"page.screenshot({ clip: {...} }) with width or height 0; clip coordinates beyond the viewport (e.g. y below the fold while fullPage is false); negative x/y pushing the rectangle fully off-screen; coordinates computed for a different viewport size or device scale factor.","commonSituations":"Capturing elements below the fold without fullPage; clip rects derived from getBoundingClientRect after the page scrolled; viewport resized between measuring and shooting; high-DPI coordinate math mistakes.","solutions":["Set fullPage: true when the target area lies outside the current viewport","Ensure clip width and height are strictly positive","Clamp x/y to the viewport: use Math.max(0, ...) on both axes and the dimensions","Prefer locator.screenshot()/elementHandle.screenshot(), which computes the rectangle for you"],"exampleFix":"// before\nawait page.screenshot({ clip: { x: 0, y: 1200, width: 300, height: 200 } }); // below the fold\n\n// after\nawait page.screenshot({ fullPage: true, clip: { x: 0, y: 1200, width: 300, height: 200 } });","handlingStrategy":"validation","validationCode":"// Intersect the clip with the viewport before shooting\nconst vp = page.viewportSize();\nconst x = Math.max(0, clip.x), y = Math.max(0, clip.y);\nconst w = Math.min(clip.width, vp.width - x), h = Math.min(clip.height, vp.height - y);\nif (w > 0 && h > 0) { await page.screenshot({ clip: { x, y, width: w, height: h } }); }\nelse { await page.screenshot({ fullPage: true, clip }); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use fullPage: true for any area at or below the fold","Never pass zero width/height in clip","Prefer element screenshots (locator.screenshot()) over manual clip math"],"tags":["browser","screenshot","viewport","validation"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}