jackwener/OpenCLI · error · EmptyResultError
guazi car ${clueId}
Error message
guazi car ${clueId} What it means
The 'guazi car' command fetched the detail page /car-detail/c<clueId>.html but parseCarDetail yielded no data rows (hasData false), so EmptyResultError is thrown. This tells you the listing detail could not be extracted — most often because the car is gone or the id is wrong — and includes the command label 'guazi car <clueId>'.
Source
Thrown at clis/guazi/car.js:100
cli({
site: 'guazi',
name: 'car',
access: 'read',
aliases: ['detail'],
description: '瓜子二手车车源详情(售价 / 上牌 / 里程 / 过户 / 配置 / 车况)',
strategy: Strategy.PUBLIC,
browser: false,
args: [
{ name: 'clue_id', required: true, positional: true, help: '车源 ID(来自 browse 的 clue_id,或 /car-detail/c<id>.html URL)' },
],
columns: CAR_COLUMNS,
func: async (args) => {
const clueId = normalizeClueId(args.clue_id);
const html = await guaziFetch(`/car-detail/c${clueId}.html`, `car ${clueId}`);
const rows = parseCarDetail(html, clueId);
if (!hasData(rows)) {
throw new EmptyResultError(
`guazi car ${clueId}`,
'No listing detail found — the car may have been sold/removed, or the id is wrong.',
);
}
const map = Object.fromEntries(rows.map((r) => [r.field, r.value]));
requireText(map.title, `guazi car ${clueId} title`);
requireText(map.price, `guazi car ${clueId} price`);
return rows;
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Verify the car still exists by opening https://m.guazi.com/car-detail/c<id>.html in a browser.
- Re-run 'guazi browse' to get a fresh list of current clue ids and pick a live one.
- Double-check the id — use normalizeClueId-accepted forms (bare number or /car-detail/c<id>.html URL).
- If the page shows content in a browser but parsing fails, update parseCarDetail selectors to the new markup.
Example fix
// before
guazi car --clue_id 100200300 // stale id
// after
const rows = await guaziBrowse({ city: 'bj' });
guazi car --clue_id rows[0].clue_id // fresh id from browse Defensive patterns
Strategy: try-catch
Validate before calling
const res = await fetch(`https://m.guazi.com/car-detail/c${clueId}.html`, { redirect: 'manual' });
if (res.status >= 300) console.warn(`car ${clueId} may be removed (status ${res.status})`); Type guard
function hasDetailRows(rows) { return Array.isArray(rows) && rows.length > 0; } Try / catch
try {
const car = await guaziCar({ clue_id: id });
} catch (e) {
if (/No listing detail found/.test(e.message)) {
console.warn(`Car ${id} unavailable; refreshing from browse`);
return null;
}
throw e;
} Prevention
- Use fresh clue ids from a recent browse call, not cached ones
- Verify the URL in a browser when a lookup fails
- Treat single-car failures as non-fatal in batch jobs
- Log the id for later re-check rather than retrying immediately
When it happens
Trigger: Calling 'guazi car --clue_id <id>' where the page loads (HTTP success) but contains no parseable detail rows: the car was sold/removed, the clue id does not exist, or the detail template changed.
Common situations: Re-using a clue id captured days earlier from a browse listing that has since sold; a typo in the id; Guazi redirecting removed cars to a generic page that still returns 200 with an empty shell.
Related errors
- No series found for '${brand}'. Check the brand name spellin
- This series has no koubei rating yet.
- ${command} returned no results
- NOT_FOUND
- guazi browse ${code}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/2949ade528015e51.
Report an issue: GitHub.