jackwener/OpenCLI · error · CommandExecutionError

autohome brand catalog returned an unexpected HTML shape; ex

Error message

autohome brand catalog returned an unexpected HTML shape; expected brand <dl> blocks.

What it means

CommandExecutionError thrown by parseBrandSeries when the Autohome brand catalog HTML contains no <dl> blocks at all. Since the parser relies on <dl> blocks holding brand/series data, their absence means the fetched page is not the expected catalog (error page, anti-bot interstitial, or redesign).

Source

Thrown at clis/autohome/brand.js:35

    BRAND_COLUMNS,
    CommandExecutionError,
    EmptyResultError,
    ahFetch,
    clean,
    requireLimit,
    requireStableId,
    requireText,
    resolveBrandInitial,
} from './utils.js';

/**
 * Pure parser: catalog HTML + brand name → series rows. Exported for tests.
 */
export function parseBrandSeries(html, brandName, limit) {
    const source = String(html || '');
    const blocks = source.match(/<dl[^>]*>[\s\S]*?<\/dl>/g);
    if (!blocks) {
        throw new CommandExecutionError('autohome brand catalog returned an unexpected HTML shape; expected brand <dl> blocks.');
    }
    const want = String(brandName || '').replace(/[·\s]/g, '');

    // No brand name (single-letter catalog mode): scan the whole page.
    // Otherwise isolate the <dl> block whose <dt> names the brand.
    let block = html;
    if (want) {
        block = null;
        for (const b of blocks) {
            const nameM = b.match(/<dt>[\s\S]*?<div>\s*<a[^>]*>([^<]+)<\/a>/);
            const name = nameM ? clean(nameM[1]).replace(/[·\s]/g, '') : '';
            if (name && (name === want || name.startsWith(want) || want.startsWith(name))) {
                block = b;
                break;
            }
        }
        if (!block) return [];
    }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry later — the page shape may be temporarily altered by anti-bot protection.
  2. Slow request rate or change network/IP to avoid the anti-bot interstitial.
  3. Check the actual HTML returned (curl the URL) to confirm whether Autohome changed markup, then update the parser regex.
  4. Verify the catalog letter URL (e.g. /grade/carhtml/A.html) is still valid in a browser.

Example fix

// before
const rows = parseBrandSeries(errorPageHtml, '宝马', 10); // throws
// after: check response sanity before parsing
const html = await ahFetch(url, 'brand A');
if (!/<dl[\s\S]*<\/dl>/.test(html)) throw new Error('unexpected autohome response, got: ' + html.slice(0, 200));
const rows = parseBrandSeries(html, '宝马', 10);
Defensive patterns

Strategy: try-catch

Validate before calling

// sanity-check HTML before parsing
if (!/<dl[\s\S]*<\/dl>/.test(html)) throw new Error('autohome page did not contain brand <dl> blocks');

Type guard

function hasBrandBlocks(html) {
  return typeof html === 'string' && /<dl[^>]*>[\s\S]*?<\/dl>/.test(html);
}

Try / catch

try {
  const rows = await brand(brandArg, limit);
} catch (e) {
  if (/unexpected HTML shape/.test(e.message)) {
    // anti-bot page or markup change; back off and retry, or surface a clear failure
    await sleep(5000);
    return retryOnce();
  }
  throw e;
}

Prevention

When it happens

Trigger: ahFetch returned HTML for /grade/carhtml/<letter>.html without any <dl> tags — e.g. an anti-bot/captcha page, a 404/soft-404 page, or Autohome changing the catalog markup.

Common situations: Autohome serving a verification page to datacenter IPs or after rapid requests; site redesign removing <dl> blocks; the letter page URL no longer existing.

Related errors


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