jackwener/OpenCLI · error · EmptyResultError
powerchina search
Error message
powerchina search
What it means
An EmptyResultError thrown by the powerchina search command when the DOM extraction produced rows, but every extracted item was classified as a navigation/portal row (site chrome like 'Home', 'English', search links) rather than a real bid entry. The library throws this to signal 'we reached the page and parsed something, but zero actual bid records matched', distinguishing it from a true empty result set or an auth wall.
Source
Thrown at clis/powerchina/search.js:218
const message = cleanText(error instanceof Error ? error.message : String(error || ''));
if (RETRYABLE_SEARCH_ERROR_HINT.test(message)) {
throw new Error(`[taxonomy=relay_unavailable] site=powerchina command=search detached browser context: ${message}`);
}
throw error;
}
}
const rows = filterNavigationRows(
dedupeCandidates(extractedRows).map((item) => ({
title: cleanText(item.title),
url: cleanText(item.url),
date: normalizeDate(cleanText(item.date)),
contextText: cleanText(item.contextText),
})),
);
if (rows.length === 0 && extractedRows.length > 0) {
throw new EmptyResultError('powerchina search', 'extracted only navigation/portal rows, no bid entries matched');
}
if (rows.length === 0) {
const pageText = cleanText(await page.evaluate('document.body ? document.body.innerText : ""'));
if (/(请先登录|未登录|登录后|验证码|人机验证)/.test(pageText)) {
throw new AuthRequiredError(
'bid.powerchina.cn',
'[taxonomy=selector_drift] site=powerchina command=search login required or human verification',
);
}
if (apiFailure) {
throw new EmptyResultError('powerchina search', `api/dom yielded no result: ${apiFailure}`);
}
}
return toProcurementSearchRecords(rows, {
site: 'powerchina',
query,View on GitHub (pinned to 49907e53dc)
Solutions
- Retry with a more specific Chinese keyword so the search page returns real bid entries instead of only portal navigation.
- Check whether bid.powerchina.cn changed its search-results markup and update the extractor/filter hints.
- Inspect the raw page (or apiFailure info) to confirm whether the query genuinely has no results.
- Fall back to the API endpoint (BidAnnouncementSummary/list) path if DOM extraction keeps returning only navigation rows.
Example fix
// before await cli search powerchina "home" // after await cli search powerchina "输变电项目 招标公告"
Defensive patterns
Strategy: validation
Validate before calling
// validate query contains bid-relevant keywords before calling
const BID_HINT = /(公告|招标|采购|中标|成交|项目|notice|tender|bidding)/i;
if (!BID_HINT.test(query)) {
throw new Error(`query "${query}" unlikely to match bid entries; add tender/procurement keywords`);
} Type guard
function hasBidResults(result) {
return Array.isArray(result?.rows) && result.rows.length > 0;
} Try / catch
try {
rows = await searchPowerchina(query);
} catch (err) {
if (err instanceof EmptyResultError && /navigation\/portal rows/.test(err.message)) {
console.warn('Only portal chrome extracted — refine query or check site markup');
rows = [];
} else throw err;
} Prevention
- Use specific Chinese procurement keywords (招标公告, 中标, 采购) in queries.
- Sanity-check the site in a real browser when a query that used to work returns only navigation rows.
- Pin/track markup-extraction filters (PROCUREMENT_TITLE_HINT) against site changes.
- Prefer the API-based extraction path when the DOM keeps yielding portal-only rows.
When it happens
Trigger: Running powerchina search where extractedRows.length > 0 but filterNavigationRows removes all of them because none match PROCUREMENT_TITLE_HINT (公告/招标/采购/中标/成交/项目/notice/tender/bidding) or all match NAVIGATION_TITLE_HINT / navigation URL patterns.
Common situations: Site layout change on bid.powerchina.cn moving bid entries into elements the extractor no longer sees; search returning only the portal shell (no results page content); query yielding zero real hits so only header/footer links were scraped; locale/English version of the site rendering titles that don't match the title hint regex.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- Ctrip round-trip flight cards rendered but parser did not fi
- Ctrip train cards rendered but parser did not find required
- Not a git repository
- 1point3acres thread
- 1point3acres user
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/65419b52d2c6b8e3.
Report an issue: GitHub.