grafana/k6 · error
checking element is hidden
Error message
checking element is hidden: %w
What it means
ElementHandle.isHidden() runs waitForElementState(['hidden']) with a zero timeout and deliberately ignores ErrTimedOut, returning a boolean for hidden/visible. A wrapped error is therefore a transport-level failure: the element handle is detached, the execution context was destroyed by navigation, or the session/frame is gone.
Solutions
- Use a live locator: await page.locator(sel).isHidden(), which re-resolves
- Check presence separately: const el = await page.$(sel); if (el === null) -> it is gone, not hidden
- Catch the error and treat it as 'no longer in DOM' when that matches the intent
- Re-acquire handles after any navigation or long wait
Example fix
// before
const el = await page.$('.toast');
await closeToast();
const hidden = await el.isHidden(); // throws: node removed from DOM
// after
await closeToast();
const gone = await page.$('.toast') === null;
const hidden = gone || await page.locator('.toast').isHidden(); Defensive patterns
Strategy: try-catch
Validate before calling
// Distinguish 'removed from DOM' from 'hidden' before checking
const gone = (await page.$('.toast')) === null;
const hidden = gone || (await page.locator('.toast').isHidden()); Try / catch
let hidden = true;
try {
hidden = await el.isHidden();
} catch (e) {
if (/not attached|Execution context|Could not find object/i.test(String(e.message))) {
hidden = (await page.$(sel)) === null; // removed counts as hidden here
} else throw e;
} Prevention
- Remember SPAs often remove (not hide) elements - page.$(sel) === null is the check for that
- Use live locators for visibility assertions
- Do not reuse handles after the flow that removes the element has run
When it happens
Trigger: The node was removed or replaced by a re-render before the check; the page navigated and the old context is gone; the element's frame was detached; the page was closed while the check ran.
Common situations: Asserting that toast/banner elements are hidden after SPAs remove them from the DOM entirely (removal is not 'hidden'); cached handles after route changes; teardown races at iteration end.
Related errors
- checking element is checked
- checking element is disabled
- checking element is editable
- checking element is enabled
- checking element is visible
AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18).
Data as JSON: /api/errors/0e32a19be6c73a8c.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/browser/common/element_handle.go:1102
}
// IsEnabled checks if the element is enabled.
func (h *ElementHandle) IsEnabled() (bool, error) {
ok, err := h.isEnabled(h.ctx, 0)
// We don't care anout timeout errors here!
if err != nil && !errors.Is(err, ErrTimedOut) {
return false, fmt.Errorf("checking element is enabled: %w", err)
}
return ok, nil
}
// 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) {View on GitHub (pinned to 3fcf5388d7)