jackwener/OpenCLI · error · CommandExecutionError

${command} selector drift${reason}

Error message

${command} selector drift${reason}

What it means

requireRows throws this CommandExecutionError when the payload's ok flag is false, meaning the page loaded but the expected DOM structure was not found — the CSS selectors the scraper relies on no longer match. The optional payload.reason from the browser side is appended for detail.

Source

Thrown at clis/dribbble/utils.js:76

    }
    if (!/(^|\.)dribbble\.com$/i.test(url.hostname)) {
        throw new ArgumentError('shot URL must use dribbble.com');
    }
    const match = url.pathname.match(/^\/shots\/(\d+)(?:-|\/|$)/);
    if (!match) throw new ArgumentError('shot URL must match dribbble.com/shots/<id>');
    return match[1];
}

export function requireRows(payload, command) {
    if (!payload || typeof payload !== 'object') {
        throw new CommandExecutionError(`${command} returned an unreadable browser payload`);
    }
    if (payload.empty) {
        throw new EmptyResultError(command, payload.reason || `${command} returned no results`);
    }
    if (!payload.ok) {
        const reason = payload.reason ? `: ${payload.reason}` : '';
        throw new CommandExecutionError(`${command} selector drift${reason}`);
    }
    if (!Array.isArray(payload.rows)) {
        throw new CommandExecutionError(`${command} returned a malformed rows payload`);
    }
    if (payload.rows.length === 0) {
        throw new EmptyResultError(command, `${command} page loaded but no matching rows were found`);
    }
    return payload.rows;
}

export function requireRow(payload, command) {
    if (!payload || typeof payload !== 'object') {
        throw new CommandExecutionError(`${command} returned an unreadable browser payload`);
    }
    if (payload.empty) {
        throw new EmptyResultError(command, payload.reason || `${command} was not found`);
    }
    if (!payload.ok || !payload.row) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Update the library to the latest version — selector fixes are typically shipped after site redesigns.
  2. Retry later or from a different network/IP if an anti-bot or consent page is the cause.
  3. Report the issue with payload.reason if updating does not fix it, so the selectors can be repaired.
  4. As a workaround, inspect the page manually to confirm whether the content still exists at all.

Example fix

// before
const rows = cli.rows('shots', payload); // 'shots selector drift'

// after
try {
  rows = cli.rows('shots', payload);
} catch (e) {
  if (String(e.message).includes('selector drift')) {
    await upgradeLibrary(); // or notify maintainers with payload.reason
    payload = await rerunBrowserCommand('shots');
    rows = cli.rows('shots', payload);
  } else throw e;
}
Defensive patterns

Strategy: fallback

Validate before calling

if (payload && payload.ok === false) {
  console.warn('Scrape reported failure before requireRows:', payload.reason || 'no reason given');
}

Type guard

function isSuccessfulPayload(p) {
  return p != null && typeof p === 'object' && p.ok === true;
}

Try / catch

try {
  rows = requireRows(payload, 'shots');
} catch (e) {
  if (e instanceof CommandExecutionError && /selector drift/.test(e.message)) {
    logForMaintainers('shots', payload && payload.reason); // site markup likely changed
    rows = []; // or fall back to a cached/alternate data source
  } else throw e;
}

Prevention

When it happens

Trigger: Dribbble redesigned their markup so the command's selectors miss; a bot-check/consent interstitial replaced the results; the page rendered an error or captcha state the scraper interprets as a failed run.

Common situations: Site layout changes after being away from updates, running an outdated version of the library against the live site, network conditions producing a partial page render, or hitting Dribbble from a datacenter IP that triggers an anti-bot wall.

Related errors


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