alibaba/page-agent · error · Error

Element at index ${index} does not have a reference

Error message

Element at index ${index} does not have a reference

What it means

Thrown when the interactive node exists in the selector map but its ref (live HTMLElement reference) is null or missing. The DOM tree keeps lightweight nodes with a back-reference to the real element; a missing ref means the node was serialized/detached or the element was removed from the document since indexing. The library refuses to operate on a node it cannot resolve to a real element.

Source

Thrown at packages/page-controller/src/actions.ts:34

	waitFor,
} from './utils'

/**
 * Get the HTMLElement by index from a selectorMap.
 * @private Internal method, subject to change at any time.
 */
export function getElementByIndex(
	selectorMap: Map<number, InteractiveElementDomNode>,
	index: number
): HTMLElement {
	const interactiveNode = selectorMap.get(index)
	if (!interactiveNode) {
		throw new Error(`No interactive element found at index ${index}`)
	}

	const element = interactiveNode.ref
	if (!element) {
		throw new Error(`Element at index ${index} does not have a reference`)
	}

	if (!isHTMLElement(element)) {
		throw new Error(`Element at index ${index} is not an HTMLElement`)
	}

	return element
}

let lastClickedElement: HTMLElement | null = null

function blurLastClickedElement() {
	if (lastClickedElement) {
		lastClickedElement.dispatchEvent(new PointerEvent('pointerout', { bubbles: true }))
		lastClickedElement.dispatchEvent(new PointerEvent('pointerleave', { bubbles: false }))
		lastClickedElement.dispatchEvent(new MouseEvent('mouseout', { bubbles: true }))
		lastClickedElement.dispatchEvent(new MouseEvent('mouseleave', { bubbles: false }))
		lastClickedElement.blur()

View on GitHub (pinned to d02db1ee7c)

Solutions

  1. Re-index with updateTree() and immediately perform the action on the fresh tree
  2. Do not serialize or structuredClone the selector map/nodes; keep actions in the same context where indexing happened
  3. If the element is genuinely gone, re-observe and choose an equivalent element
  4. Reduce the delay between observation and action on dynamic pages

Example fix

// before
await controller.inputText(7, 'hello') // node.ref === null

// after
await controller.updateTree()
await controller.inputText(7, 'hello') // fresh refs
Defensive patterns

Strategy: retry

Try / catch

try { await controller.inputText(i, text) } catch (e) { if (String(e).includes('does not have a reference')) { await controller.updateTree(); await controller.inputText(i, text) } else throw e }

Prevention

When it happens

Trigger: Element was removed from the DOM (SPA rerender, route change, list virtualization) between updateTree() and the action; tree data was structured-cloned or serialized across contexts (extension content script vs background), dropping the live ref; corrupted/partial indexing.

Common situations: Browser extension passing the dom tree through message passing which strips element references; fast-changing pages where nodes detach quickly; memory-pressure cleanup clearing refs.

Related errors


AI-assisted analysis of alibaba/page-agent@d02db1ee7c (2026-08-28). Data as JSON: /api/errors/4948cb085680c571. Report an issue: GitHub.