{"record":{"id":"7bb81d1ac9e9ddb9","repo":"jackwener/OpenCLI","slug":"github-trending-parser-drift-no-repository-rows-f","errorCode":null,"errorMessage":"github-trending parser drift: no repository rows found","messagePattern":"github-trending parser drift: no repository rows found","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/github-trending/repos.js","lineNumber":57,"sourceCode":"    if (count == null) {\n        throw new CommandExecutionError(`github-trending parser drift: missing ${field} for ${repo}`);\n    }\n    return count;\n}\n\nfunction hasExplicitEmptyTrending(html) {\n    return /don.t have any trending repositories/i.test(stripTags(html))\n        || /no trending repositories/i.test(stripTags(html));\n}\n\nfunction parseTrendingHtml(html, limit) {\n    const blocks = Array.from(String(html ?? '').matchAll(/<article\\b[^>]*class=\"[^\"]*\\bBox-row\\b[^\"]*\"[^>]*>([\\s\\S]*?)<\\/article>/g))\n        .map((match) => match[1]);\n    const rows = [];\n\n    if (blocks.length === 0) {\n        if (hasExplicitEmptyTrending(html)) return rows;\n        throw new CommandExecutionError('github-trending parser drift: no repository rows found');\n    }\n\n    for (const raw of blocks) {\n        const block = raw;\n\n        const nameMatch = block.match(/<h2\\b[\\s\\S]*?href=\"\\/([^\"/?#]+\\/[^\"/?#]+)\"/);\n        if (!nameMatch) {\n            throw new CommandExecutionError('github-trending parser drift: missing repository link');\n        }\n        const repo = decodeHtmlEntities(nameMatch[1]).trim();\n        if (!/^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/.test(repo)) {\n            throw new CommandExecutionError(`github-trending parser drift: invalid repository identity \"${repo}\"`);\n        }\n\n        const descMatch = block.match(/<p class=\"col-9 color-fg-muted[^\"]*\">([\\s\\S]*?)<\\/p>/);\n        const description = descMatch\n            ? decodeHtmlEntities(stripTags(descMatch[1]).replace(/\\s+/g, ' ')).trim()\n            : '';","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/github-trending/repos.js#L39-L75","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Retry the command — transient bot-challenges and deploys often resolve on retry","Check what the URL returns in a browser/curl to confirm whether real HTML comes back","Upgrade the CLI package to get updated parser selectors","Verify the language slug is a valid GitHub language (invalid paths may render unexpected pages)"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"null","typeGuard":"function isParserDrift(e) { return e instanceof Error && /parser drift/.test(e.message); }","tryCatchPattern":"try {\n  const rows = parseTrendingHtml(html);\n} catch (e) {\n  if (/no repository rows found/.test(e.message)) { alertMaintainer(e); return []; }\n  throw e;\n}","preventionTips":["Confirm the fetched HTML is the real trending page (not a bot-challenge) before parsing","Retry transient failures before treating them as parser drift","Keep selectors updated with new releases of the CLI"],"tags":["scraping","parser-drift","github","html-parsing"],"backgroundTag":"parser-drift-html-structure-changed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}