alibaba/page-agent · error · Error

Element at index ${index} is not an HTMLElement

Error message

Element at index ${index} is not an HTMLElement

What it means

The indexed node's ref resolved to something that is not an HTMLElement (e.g., an SVGElement, a text node, or a non-element object). All actions (click, input, select) require a real HTMLElement with the full element API, so the library guards the type before acting. It usually indicates an unexpected object ended up in the selector map or cross-realm elements from another frame/document.

Source

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

 * 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()
		lastClickedElement = null
	}
}

View on GitHub (pinned to d02db1ee7c)

Solutions

  1. Check what sits at that index via getSimplifiedHTML() and pick a real HTML element
  2. If testing, ensure the same HTMLElement realm/global is used (single jsdom instance, single library copy)
  3. Re-index after navigation so refs come from the current document
  4. Report upstream if a legitimately interactive SVG is misclassified and blocks your flow

Example fix

// before
await controller.clickElement(3) // ref is SVGElement

// after
await controller.updateTree()
// target an actual HTML element index, e.g. the parent <button>:
await controller.clickElement(2)
Defensive patterns

Strategy: type-guard

Type guard

const el = controller.element?.(i); if (el instanceof HTMLElement) { /* safe to act */ }

Try / catch

try { await controller.clickElement(i) } catch (e) { if (String(e).includes('is not an HTMLElement')) { /* pick a different index */ } else throw e }

Prevention

When it happens

Trigger: The indexed element is an SVG element or other non-HTML element; the ref came from a different document/iframe realm so instanceof HTMLElement fails; a mock or test double was injected into the tree.

Common situations: Pages with SVG-heavy UIs where an SVG node got flagged interactive; jsdom/test environments where HTMLElement globals differ between copies of the library; cross-realm elements from iframes.

Related errors


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