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
- Read the reason in the message (and Page title hint) to identify what changed
- Update the selectors inside buildExtractUisdcNewsJs in clis/uisdc/news.js to match the new DOM
- Verify manually in a browser devtools which selector broke
- 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
- Pin a snapshot test of the page DOM to catch redesigns early
- Write selectors resiliently (multiple candidates, semantic attributes)
- Return the failing selector name as the reason from the in-page script
- Monitor the site and alert on payload.ok === false
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
- Not a git repository
- Failed to extract Booking.com cards: ${err?.message || err}
- No visible Claude messages were found for conversation ${id}
- No Claude conversation history was visible on /recents.
- No visible Claude messages were found in the current convers
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/8393d6a30002ac7a.
Report an issue: GitHub.