grafana/k6 · error

describing DOM node: %w

Error message

describing DOM node: %w

What it means

During adoptElementHandle, k6 calls DOM.describeNode with the source handle's objectID to learn its backend node ID before adopting it into another execution context. The CDP call fails when the remote object behind the handle was already disposed — its objectID is invalid because the owning context was destroyed (navigation), the object was garbage collected, or the session closed.

Source

Thrown at internal/js/modules/k6/browser/common/execution_context.go:149

	e.logger.Debugf(
		"ExecutionContext:adoptElementHandle",
		"sid:%s stid:%s fid:%s ectxid:%d furl:%q ehtid:%s ehsid:%s",
		e.sid, e.stid, e.fid, e.id, e.furl,
		efid, esid)

	if eh.execCtx == e {
		return nil, errors.New("already belongs to the same execution context")
	}
	if e.frame == nil {
		return nil, errors.New("does not have a frame owner")
	}

	var node *cdp.Node
	var err error

	action := dom.DescribeNode().WithObjectID(eh.remoteObject.ObjectID)
	if node, err = action.Do(cdp.WithExecutor(e.ctx, e.session)); err != nil {
		return nil, fmt.Errorf("describing DOM node: %w", err)
	}

	return e.adoptBackendNodeID(node.BackendNodeID)
}

// eval evaluates the provided JavaScript within this execution context and
// returns a value or handle.
//
//nolint:funlen
func (e *ExecutionContext) eval(
	apiCtx context.Context, opts evalOptions, js string, args ...any,
) (any, error) {
	if escapesSobekValues(args...) {
		return nil, errors.New("sobek.Value escaped")
	}
	e.logger.Debugf(
		"ExecutionContext:eval",
		"sid:%s stid:%s fid:%s ectxid:%d furl:%q %s",

View on GitHub (pinned to 93accf6570)

Solutions

  1. Retry at the user level: re-run the query+action pair — adoption races are transient
  2. Wait for the page/frame to be idle (waitForLoadState) before querying elements
  3. Shorten handle lifetime: query, act, discard
  4. If persistent, check for repeated navigations (redirect loops) on the page
Defensive patterns

Strategy: retry

Try / catch

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

Prevention

When it happens

Trigger: waitForSelector finds an element in the utility world and adopts it into the main world while a navigation destroys contexts; cross-frame handle adoption after the source frame navigated; holding a handle long enough that Chrome garbage collects the object.

Common situations: Element queries racing page transitions in SPAs; frames/elements replaced between query and adoption inside k6's own waitForSelector path; long-running iterations keeping handles alive past navigations.

Related errors


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