grafana/k6 · error · ErrElementNotVisible
%w: %w
Error message
%w: %w
What it means
BoundingBox() maps chromium's 'Could not compute box model' CDP failure to the sentinel ErrElementNotVisible joined with the underlying error, producing 'element is not visible: getting bounding box model of DOM node: ...'. Chromium cannot compute a box model for elements with no layout object — hidden, detached, or display:none nodes.
Source
Thrown at internal/js/modules/k6/browser/common/element_handle.go:825
parts[i] = part.Body
} else {
parts[i] = part.Name + "=" + part.Body
}
}
return strings.Join(parts, " >> ")
}
// AsElement returns this element handle.
func (h *ElementHandle) AsElement() *ElementHandle {
return h
}
// BoundingBox returns this element's bounding box.
func (h *ElementHandle) BoundingBox() (*Rect, error) {
bbox, err := h.boundingBox()
if err != nil && strings.Contains(err.Error(), "Could not compute box model") {
return nil, fmt.Errorf("%w: %w", ErrElementNotVisible, err)
}
if err != nil {
return nil, fmt.Errorf("getting bounding box: %w", err)
}
return bbox, nil
}
// Click scrolls element into view and clicks in the center of the element
// TODO: look into making more robust using retries
// (see: https://github.com/microsoft/playwright/blob/master/src/server/dom.ts#L298)
func (h *ElementHandle) Click(opts *ElementHandleClickOptions) error {
click := h.newPointerAction(
func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {
return nil, handle.click(p, opts.ToMouseClickOptions())
},
&opts.ElementHandleBasePointerOptions,
)
if _, err := call(h.ctx, click, opts.Timeout); err != nil {View on GitHub (pinned to 93accf6570)
Solutions
- Wait for the element to be visible before asking for geometry
- Re-locate the element to get a live handle
- In JS, match the 'element is not visible' prefix and treat it as a soft assertion rather than a hard failure
- Ensure the element actually has layout (not display:none) when geometry is expected
Example fix
// before
const box = await handle.boundingBox(); // element is not visible: ...
// after
await page.waitForSelector(sel, { state: 'visible' });
const box = await (await page.$(sel)).boundingBox(); Defensive patterns
Strategy: validation
Validate before calling
if (!(await handle.isVisible())) {
await page.waitForSelector(sel, { state: 'visible' });
handle = await page.$(sel);
}
const box = await handle.boundingBox(); Try / catch
try {
const box = await handle.boundingBox();
} catch (e) {
if (String(e).startsWith('element is not visible')) {
// soft-fail: element hidden, no geometry exists
} else { throw e; }
} Prevention
- Never ask geometry of hidden elements; check isVisible() first
- Re-locate handles after re-renders
- Treat 'element is not visible' as an expected, matchable condition
When it happens
Trigger: boundingBox(), click, hover — anything needing geometry — on an element that is display:none/visibility:hidden, detached from the DOM, or otherwise has no layout object.
Common situations: Calling boundingBox() before render completes; element removed by a React/Vue re-render; element under a display:none ancestor; asserting geometry of hidden validation messages.
Related errors
- finding clickable point: %w
- getting bounding box: %w
- node is either not visible or not an HTMLElement: %w
- WebSocket endpoint cannot be empty
- can't fetch the page for unknown reason
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/a9ac8ae39bc02a24.
Report an issue: GitHub.