grafana/k6 · error

checking is hidden

Error message

checking is %q hidden: %w

What it means

Thrown by k6 browser's frame.isHidden(selector) when the internal visibility check cannot run at all. The code resolves the selector via Query, runs handle.isHidden (deliberately swallowing ErrTimedOut), and only errors when selector resolution or the underlying CDP call fails. A missing element is NOT an error here: it returns the default (true for isHidden).

Solutions

  1. Verify the selector is valid CSS (or a k6-supported selector engine) by testing it in DevTools
  2. Wait for navigation/load to settle before checking: page.waitForLoadState('load') or page.waitForNavigation
  3. Ensure the page is not closed or navigating when isHidden is called; check page.isClosed()
  4. Wrap the call in try-catch and treat an error as 'unknown' rather than assuming hidden

Example fix

// before
const hidden = page.isHidden('#submit');

// after
let hidden = true;
try {
  hidden = page.isHidden('#submit');
} catch (e) {
  console.log(`visibility check failed, assuming hidden: ${e}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (page.isClosed()) { throw new Error('page closed; skip isHidden check'); }
page.waitForLoadState('domcontentloaded');

Try / catch

let hidden = true; // fail-safe default
try {
  hidden = page.isHidden(sel);
} catch (e) {
  console.log(`isHidden('${sel}') unavailable: ${e}`);
}

Prevention

When it happens

Trigger: Calling page.isHidden(sel)/frame.isHidden(sel) when the wrapped Query fails: malformed CSS/XPath selector (parse error), the frame's execution context being destroyed by a concurrent navigation, or the page/target already being closed.

Common situations: k6 browser scripts that call isHidden right after page.goto() while navigation is still settling, scripts that keep operating on a page after browser.close()/test teardown, or a typo'd selector string that the CSS parser rejects.

Related errors


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

Appendix: source

Thrown at internal/js/modules/k6/browser/common/frame.go:1549

	hidden, err := f.isHidden(selector, opts)
	if err != nil {
		return false, err
	}

	return hidden, nil
}

func (f *Frame) isHidden(selector string, opts *FrameIsHiddenOptions) (bool, error) {
	isHidden := func(apiCtx context.Context, handle *ElementHandle) (any, error) {
		v, err := handle.isHidden(apiCtx) // Zero timeout when checking state
		if errors.Is(err, ErrTimedOut) {  // We don't care about timeout errors here!
			return v, nil
		}
		return v, err
	}
	v, err := f.runActionOnSelector(f.ctx, selector, opts.Strict, isHidden, func() bool { return true })
	if err != nil {
		return false, fmt.Errorf("checking is %q hidden: %w", selector, err)
	}

	return v, nil
}

// IsVisible returns true if the first element that matches the selector
// is visible. Otherwise, returns false.
func (f *Frame) IsVisible(selector string, opts *FrameIsVisibleOptions) (bool, error) {
	f.log.Debugf("Frame:IsVisible", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

	visible, err := f.isVisible(selector, opts)
	if err != nil {
		return false, err
	}

	return visible, nil
}

View on GitHub (pinned to 3fcf5388d7)