grafana/k6 · error

waiting for selector %q: adopting element handle: %w

Error message

waiting for selector %q: adopting element handle: %w

What it means

The final adoption of a found element from the utility world into the main world failed; this wraps the adoptElementHandle error, which itself covers DOM.describeNode/DOM.resolveNode failures (see 746/744). It is the same navigation/disposal race in waitForSelector's adoption path: the handle stopped being adoptable — context destroyed, object disposed, frame detached — between being found and being moved.

Source

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

	// We always return ElementHandles in the main execution context (aka "DOM world")
	f.executionContextMu.RLock()
	defer f.executionContextMu.RUnlock()

	uec := f.executionContexts[utilityWorld]

	// An element should belong to the current main world execution context, and
	// not to the utility world context, otherwise, we should adopt it to the
	// current world's execution context. This is only valid when the handle
	// is from the current frame and not part of a nested frame.
	adopted := handle
	if uec != nil && uec == handle.execCtx {
		wec := f.executionContexts[mainWorld]
		if wec == nil {
			return nil, fmt.Errorf("waiting for selector %q: execution context %q not found", selector, mainWorld)
		}

		if adopted, err = wec.adoptElementHandle(handle); err != nil {
			return nil, fmt.Errorf("waiting for selector %q: adopting element handle: %w", selector, err)
		}

		if err = handle.Dispose(); err != nil {
			f.log.Warnf(
				"Frame:waitForSelector",
				"fid:%s furl:%q sel:%q disposing element handle: %v",
				f.ID(), f.URL(), selector, err,
			)
		}
	}

	return adopted, nil
}

func (f *Frame) waitFor(
	selector string, opts *FrameWaitForSelectorOptions, retryCount int,
) (_ *ElementHandle, rerr error) {
	f.log.Debugf("Frame:waitFor", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

View on GitHub (pinned to 93accf6570)

Solutions

  1. Retry the wait — the element will be re-found in the new context without adoption
  2. Stabilize timing with waitForLoadState before querying
  3. Prefer one-shot selector-action APIs (page.click(sel)) which handle retries internally
Defensive patterns

Strategy: retry

Try / catch

try {
  el = await page.waitForSelector('#x');
} catch (e) {
  if (/adopting element handle/.test(e.message)) {
    await page.waitForLoadState();
    el = await page.waitForSelector('#x');
  } else throw e;
}

Prevention

When it happens

Trigger: waitForSelector racing a navigation (describeNode fails on a disposed object during adoption); the element removed by a re-render mid-adoption; cross-frame handles whose source frame navigated.

Common situations: Fast SPA transitions during waits; elements replaced by animations or virtual scrolling; load-induced disposal of remote objects.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/97ef4a90c0bbdd42. Report an issue: GitHub.