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
- Retry the wait — the element will be re-found in the new context without adoption
- Stabilize timing with waitForLoadState before querying
- 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
- Prefer one-shot selector-action APIs (page.click(sel)) which retry internally
- Stabilize the page before querying on animation/virtual-scroll UIs
- Do not store handles across re-render boundaries
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
- waiting for selector %q: execution context %q not found
- getting injected script: %w
- getting frame content: %w
- evaluating handle for frame: execution context %q not found
- getting node in frame: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/97ef4a90c0bbdd42.
Report an issue: GitHub.