grafana/k6 · error · ErrElementNotVisible
%w: %w
Error message
%w: %w
What it means
BoundingBox() wraps its lower-level call: when the underlying error text contains 'Could not compute box model' (Chrome's response for elements with no layout box), k6 re-wraps it with ErrElementNotVisible using Go's multi-%w, so errors.Is(err, ErrElementNotVisible) matches. The element exists but has no computable geometry.
Solutions
- Wait for visibility before geometry-dependent calls: await el.waitFor({ state: 'visible' })
- Reveal the container (open the tab/accordion) before measuring
- Treat ErrElementNotVisible explicitly in Go code with errors.Is to distinguish it from session errors
- Re-query the element after SPA re-renders rather than caching handles
Example fix
// before
const box = await el.boundingBox();
// after
await el.waitFor({ state: 'visible' });
const box = await el.boundingBox(); Defensive patterns
Strategy: validation
Validate before calling
if (!(await el.isVisible())) {
await el.waitFor({ state: 'visible', timeout: 10_000 });
}
const box = await el.boundingBox(); Try / catch
try {
const box = await el.boundingBox();
} catch (e) {
if (/element is not visible/.test(String(e))) {
await el.waitFor({ state: 'visible' });
const box = await el.boundingBox();
} else throw e;
} Prevention
- Wait for visible state before any geometry call (boundingBox, click, screenshot)
- Reveal hidden containers (tabs, accordions) before measuring their children
- In Go extensions, branch on errors.Is(err, ErrElementNotVisible) instead of string matching
When it happens
Trigger: Calling BoundingBox(), click(), screenshot-of-element, or any geometry-dependent API on an element with display:none, visibility:hidden collapse, or detached-from-layout state; the CDP GetBoxModel call at element_handle.go:67 succeeds/fails with the 'Could not compute box model' message and gets dual-wrapped here.
Common situations: Elements in hidden tabs, collapsed accordions, or before CSS/animation layout completes; shadow-DOM content not yet rendered; checking geometry of elements removed by SPA re-render between query and call.
Related errors
- finding clickable point
- finding offset position
- getting bounding box of parent frame
- getting bounding box
- pointer action
AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18).
Data as JSON: /api/errors/a9ac8ae39bc02a24.
Report an issue: GitHub.
Appendix: 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 3fcf5388d7)