jackwener/OpenCLI · error · CommandExecutionError

github-trending parser drift: no repository rows found

Error message

github-trending parser drift: no repository rows found

What it means

parseTrendingHtml found zero `<article class="Box-row">` blocks in the fetched GitHub Trending HTML. If the page does not explicitly say there are no trending repositories, the library assumes the page layout changed and throws this CommandExecutionError rather than silently returning an empty list — this is a scraper-integrity safeguard against parser drift.

Source

Thrown at clis/github-trending/repos.js:57

    if (count == null) {
        throw new CommandExecutionError(`github-trending parser drift: missing ${field} for ${repo}`);
    }
    return count;
}

function hasExplicitEmptyTrending(html) {
    return /don.t have any trending repositories/i.test(stripTags(html))
        || /no trending repositories/i.test(stripTags(html));
}

function parseTrendingHtml(html, limit) {
    const blocks = Array.from(String(html ?? '').matchAll(/<article\b[^>]*class="[^"]*\bBox-row\b[^"]*"[^>]*>([\s\S]*?)<\/article>/g))
        .map((match) => match[1]);
    const rows = [];

    if (blocks.length === 0) {
        if (hasExplicitEmptyTrending(html)) return rows;
        throw new CommandExecutionError('github-trending parser drift: no repository rows found');
    }

    for (const raw of blocks) {
        const block = raw;

        const nameMatch = block.match(/<h2\b[\s\S]*?href="\/([^"/?#]+\/[^"/?#]+)"/);
        if (!nameMatch) {
            throw new CommandExecutionError('github-trending parser drift: missing repository link');
        }
        const repo = decodeHtmlEntities(nameMatch[1]).trim();
        if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repo)) {
            throw new CommandExecutionError(`github-trending parser drift: invalid repository identity "${repo}"`);
        }

        const descMatch = block.match(/<p class="col-9 color-fg-muted[^"]*">([\s\S]*?)<\/p>/);
        const description = descMatch
            ? decodeHtmlEntities(stripTags(descMatch[1]).replace(/\s+/g, ' ')).trim()
            : '';

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the command — transient bot-challenges and deploys often resolve on retry
  2. Check what the URL returns in a browser/curl to confirm whether real HTML comes back
  3. Upgrade the CLI package to get updated parser selectors
  4. Verify the language slug is a valid GitHub language (invalid paths may render unexpected pages)
Defensive patterns

Strategy: fallback

Validate before calling

null

Type guard

function isParserDrift(e) { return e instanceof Error && /parser drift/.test(e.message); }

Try / catch

try {
  const rows = parseTrendingHtml(html);
} catch (e) {
  if (/no repository rows found/.test(e.message)) { alertMaintainer(e); return []; }
  throw e;
}

Prevention

When it happens

Trigger: Fetching /trending (or a language-filtered trending path) returns HTML with no Box-row article elements and no 'don't have any trending repositories' message — e.g. a login wall, bot-challenge page, empty/error page, or a GitHub markup change.

Common situations: GitHub A/B-testing a redesigned trending page; response being an interstitial (rate-limit, sign-in, or CAPTCHA page); language path with genuinely no trending repos rendered differently than the empty-state text the parser checks; CDN/error page returned instead of real HTML.

Related errors


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