jackwener/OpenCLI · error · CommandExecutionError

UISDC news selector drift: ${reason}

Error message

UISDC news selector drift: ${reason}

What it means

When the in-page extractor reports payload.ok === false, toRows throws CommandExecutionError 'UISDC news selector drift: <reason>'. This means the page structure changed so the extraction selectors no longer matched; the reason defaults to 'selector-drift' or carries the page-reported reason string, and the page title is attached as a hint.

Source

Thrown at clis/uisdc/news.js:58

          return {
            rank: index + 1,
            title: el.querySelector('.dubao-title')?.textContent || '',
            summary: el.querySelector('.dubao-content')?.textContent || '',
            url: anchor ? new URL(anchor.getAttribute('href'), location.href).href : '',
          };
        });
        return { ok: true, rows };
      })()
    `;
}

function toRows(payload, limit) {
    if (!payload || typeof payload !== 'object') {
        throw new CommandExecutionError('UISDC news page returned an unreadable payload');
    }
    if (!payload.ok) {
        const reason = typeof payload.reason === 'string' && payload.reason.trim() ? payload.reason.trim() : 'selector-drift';
        throw new CommandExecutionError(
            `UISDC news selector drift: ${reason}`,
            payload.title ? `Page title: ${payload.title}` : undefined,
        );
    }
    const rows = (Array.isArray(payload.rows) ? payload.rows : [])
        .map((row, index) => ({
            rank: index + 1,
            title: normalizeText(row.title),
            summary: normalizeText(row.summary),
            url: normalizeText(row.url),
        }))
        .filter((row) => row.title && row.url);
    if (rows.length === 0) {
        throw new EmptyResultError('uisdc news', 'UISDC news page loaded, but no news rows with title and URL were extracted.');
    }
    return rows.slice(0, limit).map((row, index) => ({ ...row, rank: index + 1 }));
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the reason in the message (and Page title hint) to identify what changed
  2. Update the selectors inside buildExtractUisdcNewsJs in clis/uisdc/news.js to match the new DOM
  3. Verify manually in a browser devtools which selector broke
  4. If caused by slow loading, increase settleMs or wait for the specific node before extracting

Example fix

// before
const rows = [...document.querySelectorAll('.news-list li')];
// after
const rows = [...document.querySelectorAll('.news-list li, .article-list__item')];
Defensive patterns

Strategy: try-catch

Validate before calling

const probe = await page.$('.news-list li'); if (!probe) throw new Error('selector drift: .news-list li missing');

Type guard

function isOkPayload(p) { return !!p && typeof p === 'object' && p.ok === true && Array.isArray(p.rows); }

Try / catch

try { const rows = await loadUisdcNews(page, args); } catch (e) { if (/selector drift/.test(e.message)) { reportDrift(e.message, e.hint); return cachedRows; } throw e; }

Prevention

When it happens

Trigger: UISDC redesigned its news page HTML so the extract script's selectors find no nodes and it returns {ok:false, reason}; the script's own failure path sets a custom reason string.

Common situations: Site redesign or A/B test changing DOM classes; lazy-loaded content not present when the script runs; region-specific markup differences.

Related errors


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