{"record":{"id":"15eb956e02cfd718","repo":"grafana/k6","slug":"node-is-either-not-visible-or-not-an-htmlelement","errorCode":null,"errorMessage":"node is either not visible or not an HTMLElement: %w","messagePattern":"node is either not visible or not an HTMLElement: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/screenshotter.go","lineNumber":286,"sourceCode":"\n\treturn visualViewportScale, visualViewportPageX, visualViewportPageY, nil\n}\n\nfunc (s *screenshotter) screenshotElement(h *ElementHandle, opts *ElementHandleScreenshotOptions) ([]byte, error) {\n\tformat := opts.Format\n\tviewportSize, originalViewportSize, err := s.originalViewportSize(h.frame.page)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting original viewport size: %w\", err)\n\t}\n\n\terr = h.waitAndScrollIntoViewIfNeeded(h.ctx, false, true, opts.Timeout)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"scrolling element into view: %w\", err)\n\t}\n\n\tbbox, err := h.boundingBox()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"node is either not visible or not an HTMLElement: %w\", err)\n\t}\n\tif bbox.Width <= 0 {\n\t\treturn nil, fmt.Errorf(\"node has 0 width\")\n\t}\n\tif bbox.Height <= 0 {\n\t\treturn nil, fmt.Errorf(\"node has 0 height\")\n\t}\n\n\tvar overriddenViewportSize *Size\n\tfitsViewport := bbox.Width <= viewportSize.Width && bbox.Height <= viewportSize.Height\n\tif !fitsViewport { //nolint:nestif\n\t\toverriddenViewportSize = Size{\n\t\t\tWidth:  math.Max(viewportSize.Width, bbox.Width),\n\t\t\tHeight: math.Max(viewportSize.Height, bbox.Height),\n\t\t}.enclosingIntSize()\n\t\tif err := h.frame.page.setViewportSize(overriddenViewportSize); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"setting viewport size to %s: %w\",\n\t\t\t\toverriddenViewportSize, err)","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/screenshotter.go#L268-L304","documentation":"After scrolling into view, elementHandle.screenshot() calls boundingBox() to get the element's box; that call errored, which the message renders as 'node is either not visible or not an HTMLElement'. boundingBox returns null/error for elements with no layout box: display:none, detached nodes, or non-HTMLElement nodes.","triggerScenarios":"elementHandle.screenshot() on an element that is display:none / visibility:hidden / position:fixed with no box, an element removed from the DOM between wait and boundingBox, or a handle to a text/comment node.","commonSituations":"Hidden-by-CSS widgets (tabs, modals not yet opened); anti-bot CSS hiding content; stale handles in SPAs after re-render; elements inside closed shadow roots resolved incorrectly.","solutions":["Make the element visible first: open the tab/modal/accordion or remove hiding CSS, then await locator.waitFor({state:'visible'}).","Re-resolve the handle right before the screenshot to avoid stale references.","If you must capture it, temporarily force layout (e.g. page.evaluate to set style.display='block') — or screenshot the page with a clip rect instead.","Verify your selector matches a real visible element (log await locator.isVisible())."],"exampleFix":"// before\nawait page.$('.hidden-panel').then(el => el.screenshot({ path: 'p.png' })); // display:none\n\n// after\nconst panel = page.locator('.hidden-panel');\nawait page.evaluate(\"document.querySelector('.hidden-panel').style.display = 'block'\");\nawait panel.waitFor({ state: 'visible' });\nawait panel.screenshot({ path: 'p.png' });","handlingStrategy":"validation","validationCode":"if (!(await locator.isVisible())) throw new Error('element not visible; open it before screenshot');","typeGuard":"async function hasLayoutBox(loc) {\n  const bb = await loc.boundingBox();\n  return bb !== null && bb.width > 0 && bb.height > 0;\n}","tryCatchPattern":"try { await el.screenshot({ path: 'e.png' }); }\ncatch (e) { if (String(e).includes('not visible or not an HTMLElement')) { /* reveal element, retry */ } else throw e; }","preventionTips":["Check locator.isVisible() before screenshotting.","Open modals/tabs that contain the target element first.","Re-resolve handles in SPAs right before use."],"tags":["k6","browser","screenshot","element-handle","visibility","bounding-box"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}