grafana/k6 · warning

already belongs to the same execution context

Error message

already belongs to the same execution context

What it means

ExecutionContext.adoptElementHandle (execution_context.go:106-141) re-creates an ElementHandle inside a different execution context by resolving its backend node. If the handle's context is already this exact context (eh.execCtx == e), adoption is pointless and the method refuses with this error rather than silently no-opping.

Source

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

func (e *ExecutionContext) adoptElementHandle(eh *ElementHandle) (*ElementHandle, error) {
	var (
		efid cdp.FrameID
		esid target.SessionID
	)
	if eh.frame != nil {
		efid = cdp.FrameID(eh.frame.ID())
	}
	if eh.session != nil {
		esid = eh.session.ID()
	}
	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.

View on GitHub (pinned to 01ffac6f24)

Solutions

  1. If you control the call path, compare the handle's owning context/frame before adopting and skip when they already match
  2. Re-query the element in the target frame instead of adopting an existing handle
  3. Dispose the old handle and use page.$/frame.$ on the current frame to get a handle in the right context
  4. Upgrade k6: internal waitForSelector logic (frame.go:513) already checks worlds, so newer builds narrow this race
Defensive patterns

Strategy: try-catch

Try / catch

try {
  adopted = await targetFrame.adoptElementHandle(handle);
} catch (e) {
  if (/already belongs/.test(e.message)) {
    adopted = handle; // already in the right context; just use it
  } else throw e;
}

Prevention

When it happens

Trigger: Calling adoption paths where source and target context are identical. User scripts rarely call this directly; it is reachable via frame/frameElement flows and waitForSelector's adoption step (frame.go:513-521), which guards it by comparing worlds first — so hitting it usually means an internal race during navigation reassigned the handle's context.

Common situations: Surfaces as an inner error inside waitForSelector/frame operations during rapid navigation when a handle's world flipped between the check and the adoption; mostly seen in k6 logs rather than as the primary script error.

Related errors


AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18). Data as JSON: /api/errors/e7e9b41a86f65ead. Report an issue: GitHub.