jackwener/OpenCLI · error · CommandExecutionError

Booking.com page declared results but no property cards were

Error message

Booking.com page declared results but no property cards were parsed: ${totalText}

What it means

This CommandExecutionError is thrown when the extractor returned an empty items array but the page's own result-count text (raw.totalText) indicates a positive number of results. It distinguishes 'genuinely no results' (which raises EmptyResultError, see 528) from 'results exist but parsing failed' — a scraping/selector mismatch.

Source

Thrown at clis/booking/search.js:298

    if (!raw || typeof raw !== 'object') {
      throw new CommandExecutionError('Booking.com page returned no extractable data');
    }
    if (raw.blocked) {
      throw new CommandExecutionError('Booking.com served a verification / captcha page; retry later or change profile');
    }

    if (raw.ok !== true) {
      throw new CommandExecutionError('Booking.com extractor returned an invalid status');
    }
    if (!Array.isArray(raw.items)) {
      throw new CommandExecutionError('Booking.com extractor returned malformed items');
    }

    const items = raw.items;
    if (items.length === 0) {
      const totalText = String(raw.totalText || '').trim();
      if (hasPositiveResultCount(totalText)) {
        throw new CommandExecutionError(
          `Booking.com page declared results but no property cards were parsed: ${totalText}`,
        );
      }
      throw new EmptyResultError(
        `booking search ${JSON.stringify(destination)}`,
        totalText
          ? `No hotels rendered (${totalText}). Try a broader destination, different dates, or check the URL in a browser.`
          : 'No hotels rendered. Try a broader destination, different dates, or check the URL in a browser.',
      );
    }

    return items.slice(0, limit).map((it, i) => {
      if (!it || typeof it !== 'object') {
        throw new CommandExecutionError('Booking.com extractor returned malformed hotel row');
      }
      const name = String(it.name || '').trim();
      const country = String(it.country || '').trim();
      const slug = String(it.slug || '').trim();

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Update the library so the property-card selector matches Booking.com's current markup.
  2. Retry — cards may not have finished lazy-loading; allow a longer settle time before extraction.
  3. Check whether the page rendered a non-default view (map/grid) and force the standard list view in the URL.
  4. Open the same URL in a regular browser to confirm cards are present, then compare DOM.
  5. If a captcha/verification overlay appeared, switch profile/IP (related to blocked detection).

Example fix

// before (wait once for first card)
await page.wait('selector', '[data-testid=property-card]', { timeoutMs: 20000 }).catch(() => {});
// after (also wait for more cards to lazy-load)
await page.wait('selector', '[data-testid=property-card]', { timeoutMs: 20000 }).catch(() => {});
await page.evaluate(() => window.scrollBy(0, 2000));
await new Promise(r => setTimeout(r, 3000));
Defensive patterns

Strategy: retry

Validate before calling

// check the URL will render the standard list view
const url = new URL(searchUrl);
if (url.searchParams.get('nflt') && url.searchParams.get('nflt').includes('view')) console.warn('view filters may hide property cards');

Try / catch

try {
  return await booking.search(params);
} catch (e) {
  if (/declared results but no property cards were parsed/.test(e.message)) {
    await sleep(5000);            // let lazy-load finish
    return booking.search(params);
  }
  throw e;
}

Prevention

When it happens

Trigger: items.length === 0 AND hasPositiveResultCount(totalText) is true — e.g. totalText like '1,024 properties found' while zero property cards were parsed from the DOM.

Common situations: Booking.com changed its card markup (data-testid renamed) so the selector matches nothing; page was still lazy-loading cards when extraction ran despite the 20s wait; results rendered inside a different container (map view, list-vs-grid toggle); partial bot-block that kept the header but replaced cards.

Related errors


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