jackwener/OpenCLI · error

DOM node not found

Error message

DOM node not found

What it means

clickWithQuads resolves the CSS selector via CDP DOM.querySelectorAll against the document. If no matching nodes are returned it throws 'DOM node not found' before attempting quad-based clicking.

Source

Thrown at src/browser/page.ts:370

    // Scroll element into view first
    await this.evaluate(`
      (() => {
        const el = document.querySelector('[data-opencli-ref="' + ${safeRef} + '"]');
        if (el) el.scrollIntoView({ behavior: 'instant', block: 'center' });
        return !!el;
      })()
    `);

    try {
      // Find DOM node via CDP
      const doc = await this.cdp('DOM.getDocument', {}) as { root: { nodeId: number } };
      const result = await this.cdp('DOM.querySelectorAll', {
        nodeId: doc.root.nodeId,
        selector: cssSelector,
      }) as { nodeIds: number[] };

      if (!result.nodeIds?.length) throw new Error('DOM node not found');

      const nodeId = result.nodeIds[0];

      // Try getContentQuads first (precise for inline elements)
      try {
        const quads = await this.cdp('DOM.getContentQuads', { nodeId }) as { quads: number[][] };
        if (quads.quads?.length) {
          const q = quads.quads[0];
          const cx = (q[0] + q[2] + q[4] + q[6]) / 4;
          const cy = (q[1] + q[3] + q[5] + q[7]) / 4;
          await this.nativeClick(Math.round(cx), Math.round(cy));
          return;
        }
      } catch { /* fallthrough */ }

      // Try getBoxModel
      try {
        const box = await this.cdp('DOM.getBoxModel', { nodeId }) as { model: { content: number[] } };

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the selector matches in the page console: document.querySelectorAll(sel).length
  2. Wait for the element to appear (e.g. waitForSelector/polling) before clicking
  3. Use a snapshot ref instead of a raw CSS selector
  4. Ensure the element is not inside a shadow root or iframe the CDP document query misses

Example fix

// before
await page.clickWithQuads('.submit-btn', ...);
// after
await page.waitForSelector('.submit-btn');
await page.clickWithQuads('.submit-btn', ...);
Defensive patterns

Strategy: validation

Validate before calling

const n = await page.evaluate(`document.querySelectorAll(${JSON.stringify(sel)}).length`);
if (!n) throw new Error(`selector ${sel} matches nothing`);

Type guard

function hasNodes(r: { nodeIds?: number[] } | null): r is { nodeIds: number[] } {
  return Array.isArray(r?.nodeIds) && r.nodeIds.length > 0;
}

Try / catch

try { await page.clickWithQuads(sel, ...); }
catch (e) {
  if (e.message === 'DOM node not found') {
    await page.waitForSelector(sel);
    await page.clickWithQuads(sel, ...);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling page.clickWithQuads(selector, ...) with a CSS selector that matches zero elements in the current document at CDP level.

Common situations: Selector typo; element rendered after an async load/spinner; element inside an iframe or shadow DOM not covered by document.querySelectorAll; page navigated between snapshot and click.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/43ad07f45de30fd7. Report an issue: GitHub.