grafana/k6 · error

checking element is visible

Error message

checking element is visible: %w

What it means

ElementHandle.isVisible() runs waitForElementState(['visible']) with a zero timeout and intentionally ignores ErrTimedOut so that ordinary 'not visible yet' situations return false. A wrapped error means the check itself could not run: the element handle is detached/stale, the execution context was destroyed by navigation, or the frame/session closed.

Solutions

  1. Use a live locator: await page.locator(sel).isVisible(), which re-resolves the element
  2. Re-acquire the handle immediately before the visibility check
  3. Wrap in try/catch and treat the error as 'element gone' if that is the semantic you want
  4. Do not keep element handles across navigations or long asynchronous flows

Example fix

// before
const el = await page.$('.spinner');
await doWork();
const visible = await el.isVisible(); // throws: spinner unmounted

// after
await doWork();
const visible = await page.locator('.spinner').isVisible();
Defensive patterns

Strategy: try-catch

Validate before calling

// Live visibility check that re-resolves the element
const visible = await page.locator('.spinner').isVisible();

Try / catch

let visible = false;
try {
  visible = await el.isVisible();
} catch (e) {
  if (/not attached|Execution context|Could not find object/i.test(String(e.message))) {
    visible = (await page.$(sel)) !== null && await page.locator(sel).isVisible();
  } else throw e;
}

Prevention

When it happens

Trigger: The element node was replaced or removed by an SPA re-render between query and check; the page navigated away, invalidating the handle's context; the element lives in a closed iframe; the browser session terminated.

Common situations: Visibility guards on spinner/loading indicators that get unmounted; handles cached across page.goto(); checks racing logout, popup close, or iteration teardown.

Related errors


AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18). Data as JSON: /api/errors/eecbfa6713d65c09. Report an issue: GitHub.

Appendix: source

Thrown at internal/js/modules/k6/browser/common/element_handle.go:1113

}

// IsHidden checks if the element is hidden.
func (h *ElementHandle) IsHidden() (bool, error) {
	ok, err := h.isHidden(h.ctx)
	// We don't care anout timeout errors here!
	if err != nil && !errors.Is(err, ErrTimedOut) {
		return false, fmt.Errorf("checking element is hidden: %w", err)
	}

	return ok, nil
}

// IsVisible checks if the element is visible.
func (h *ElementHandle) IsVisible() (bool, error) {
	ok, err := h.isVisible(h.ctx)
	// We don't care anout timeout errors here!
	if err != nil && !errors.Is(err, ErrTimedOut) {
		return false, fmt.Errorf("checking element is visible: %w", err)
	}

	return ok, nil
}

// OwnerFrame returns the frame containing this element.
func (h *ElementHandle) OwnerFrame() (_ *Frame, rerr error) {
	fn := `
		(node, injected) => {
			return injected.getDocumentElement(node);
		}
	`
	opts := evalOptions{
		forceCallable: true,
		returnByValue: false,
	}
	res, err := h.evalWithScript(h.ctx, opts, fn)
	if err != nil {

View on GitHub (pinned to 3fcf5388d7)