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

  1. Wait for visibility before geometry-dependent calls: await el.waitFor({ state: 'visible' })
  2. Reveal the container (open the tab/accordion) before measuring
  3. Treat ErrElementNotVisible explicitly in Go code with errors.Is to distinguish it from session errors
  4. 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

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


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)