jackwener/OpenCLI · error · CommandExecutionError

${label} did not include a stable text value.

Error message

${label} did not include a stable text value.

What it means

requireText cleans whitespace from an extracted value and throws CommandExecutionError when the result is empty, using the caller's label (e.g. 'guazi car 100200300 title'). It guards against HTML pages that return 200 but fail to contain the expected field, which would otherwise silently produce blank data.

Source

Thrown at clis/guazi/utils.js:95

    return m[1];
}

export function requireLimit(value, def, max) {
    const raw = value == null || value === '' ? def : value;
    const n = typeof raw === 'number' ? raw : Number(String(raw).trim());
    if (!Number.isInteger(n) || n < 1 || n > max) {
        throw new ArgumentError(`limit must be an integer between 1 and ${max}`);
    }
    return n;
}

export function clean(s) {
    return String(s == null ? '' : s).replace(/\s+/g, ' ').trim();
}

export function requireText(value, label) {
    const text = clean(value);
    if (!text) throw new CommandExecutionError(`${label} did not include a stable text value.`);
    return text;
}

export function requireStableId(value, label) {
    const id = String(value ?? '').trim();
    if (!/^\d+$/.test(id)) throw new CommandExecutionError(`${label} did not include a stable numeric id.`);
    return id;
}

/** Fetch a Guazi mobile page as HTML text, throwing typed errors. */
export async function guaziFetch(path, contextHint) {
    let resp;
    try {
        resp = await fetch(`${GUAZI_M_BASE}${path}`, {
            headers: {
                'User-Agent': UA,
                Referer: `${GUAZI_M_BASE}/`,
                'Accept-Language': 'zh-CN,zh;q=0.9',

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Open the detail page in a browser and confirm the title renders in server HTML; if not, the layout/rendering changed.
  2. Update the parser in clis/guazi/car.js to select the new title element so requireText receives a value.
  3. Re-run with a different car id to determine whether it is page-specific or template-wide.
  4. If pages are bot-degraded, add proper headers/cookies or slow request rate before retrying.

Example fix

// before
const title = doc.querySelector('.car-name')?.textContent;
// after (selector updated to current markup)
const title = doc.querySelector('h1.car-title, .detail-title')?.textContent;
Defensive patterns

Strategy: try-catch

Validate before calling

const text = (value ?? '').replace(/\s+/g, ' ').trim();
if (!text) console.warn(`No text extracted for ${label} — check page markup`);

Type guard

function hasText(v): v is string {
  return typeof v === 'string' && v.replace(/\s+/g, ' ').trim().length > 0;
}

Try / catch

try {
  const car = await guaziCar({ clue_id: id });
} catch (e) {
  if (/did not include a stable text value/.test(e.message)) {
    console.warn(`Field missing for car ${id}; page template may have changed`);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: 'guazi car <clueId>' found rows but the title field parsed to null/empty/whitespace — e.g. the detail template renamed the title element, the field moved behind JS rendering, or anti-bot returned a degraded page shell.

Common situations: Guazi redesign moving the <h1>/title node; scraping a page where the listing exists but title loads client-side; empty string in a scraped <td> due to a layout variant; partial page served to suspected bots.

Related errors


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