{"record":{"id":"0619dca5f5fa5e53","repo":"jackwener/OpenCLI","slug":"uisdc-news-page-loaded-but-no-news-rows-with-titl","errorCode":null,"errorMessage":"UISDC news page loaded, but no news rows with title and URL were extracted.","messagePattern":"UISDC news page loaded, but no news rows with title and URL were extracted\\.","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"warning","filePath":"clis/uisdc/news.js","lineNumber":72,"sourceCode":"        throw new CommandExecutionError('UISDC news page returned an unreadable payload');\n    }\n    if (!payload.ok) {\n        const reason = typeof payload.reason === 'string' && payload.reason.trim() ? payload.reason.trim() : 'selector-drift';\n        throw new CommandExecutionError(\n            `UISDC news selector drift: ${reason}`,\n            payload.title ? `Page title: ${payload.title}` : undefined,\n        );\n    }\n    const rows = (Array.isArray(payload.rows) ? payload.rows : [])\n        .map((row, index) => ({\n            rank: index + 1,\n            title: normalizeText(row.title),\n            summary: normalizeText(row.summary),\n            url: normalizeText(row.url),\n        }))\n        .filter((row) => row.title && row.url);\n    if (rows.length === 0) {\n        throw new EmptyResultError('uisdc news', 'UISDC news page loaded, but no news rows with title and URL were extracted.');\n    }\n    return rows.slice(0, limit).map((row, index) => ({ ...row, rank: index + 1 }));\n}\n\nasync function loadUisdcNews(page, args) {\n    const limit = normalizeLimit(args.limit);\n    await page.goto(UISDC_NEWS_URL, { waitUntil: 'load', settleMs: 3000 });\n    const payload = await page.evaluate(buildExtractUisdcNewsJs()).catch((error) => {\n        throw new CommandExecutionError(`Failed to extract UISDC news: ${getErrorMessage(error)}`);\n    });\n    return toRows(payload, limit);\n}\n\nexport const uisdcNewsCommand = cli({\n    site: 'uisdc',\n    name: 'news',\n    access: 'read',\n    description: '优设读报 - 最新 AI/设计行业新闻',","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/uisdc/news.js#L54-L90","documentation":"After extraction, toRows filters rows to those having both a title and URL. If none survive, it throws EmptyResultError 'UISDC news page loaded, but no news rows with title and URL were extracted.' — the page loaded fine, but zero usable news items were found.","triggerScenarios":"The extracted rows array is empty or every row lacks a non-empty title or url after normalizeText trimming (e.g. blank page, empty news list, partially rendered content).","commonSituations":"Site returned a valid but empty news page (holiday/maintenance); rows render via JS after the 3000ms settle window; selectors matched a container but items have different field markup so title/url come back empty.","solutions":["Re-run the command later — the site may temporarily have no items","Increase settleMs in loadUisdcNews's page.goto call to let JS-rendered content appear","Check the selectors for row.title/row.url fields in buildExtractUisdcNewsJs; container may match but fields don't","Confirm in a browser that the news list actually has items at UISDC_NEWS_URL"],"exampleFix":"// before\nawait page.goto(UISDC_NEWS_URL, { waitUntil: 'load', settleMs: 3000 });\n// after\nawait page.goto(UISDC_NEWS_URL, { waitUntil: 'load', settleMs: 8000 });","handlingStrategy":"fallback","validationCode":"const itemCount = await page.locator('.news-list li').count(); if (itemCount === 0) await page.waitForSelector('.news-list li', { timeout: 10000 });","typeGuard":"function hasUsableRows(rows) { return Array.isArray(rows) && rows.some(r => r.title && r.url); }","tryCatchPattern":"try { const rows = await loadUisdcNews(page, args); } catch (e) { if (e instanceof EmptyResultError || /no news rows/.test(e.message)) { return []; } throw e; }","preventionTips":["Increase settleMs or wait for the row selector before evaluating","Handle legitimately empty news periods by treating this as an empty result, not a crash","Validate that title/url sub-selectors still match when the container selector changes","Cache last-known-good rows to soften transient empty extractions"],"tags":["scraping","empty-result","dom"],"backgroundTag":"empty-scrape-result","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}