jackwener/OpenCLI · error · CommandExecutionError

Booking.com extractor returned malformed hotel row

Error message

Booking.com extractor returned malformed hotel row

What it means

This CommandExecutionError is thrown while mapping individual extractor items when an element is not a usable object (null, undefined, or a non-object). The library validates each hotel row before normalizing its fields (name, country, slug, url), so a single malformed row aborts the whole result mapping rather than silently emitting garbage.

Source

Thrown at clis/booking/search.js:312

    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();
      const urlValue = String(it.url || '').trim();
      const expectedUrl = country && slug
        ? `https://www.booking.com/hotel/${country}/${slug}.html`
        : '';
      if (!name || !/^[a-z]{2}$/.test(country) || !slug || urlValue !== expectedUrl) {
        throw new CommandExecutionError('Booking.com hotel row is missing stable name/url identity');
      }
      return {
        rank: offset + i + 1,
        name,
        country,
        slug,
        star_rating: it.star_rating,
        review_score: it.review_score,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Update the library so the extractor never emits non-object rows.
  2. Log raw.items to find the offending entry and its index.
  3. Retry the search — a lazy-load race may produce complete rows on a second attempt.
  4. If using a custom extractor, filter falsy rows before returning: items.filter(it => it && typeof it === 'object').

Example fix

// before (custom extractor)
return { ok: true, items: cards.map(parseCard) };
// after
return { ok: true, items: cards.map(parseCard).filter(it => it && typeof it === 'object') };
Defensive patterns

Strategy: type-guard

Validate before calling

// pre-filter raw items yourself if you control the extractor output
const safeItems = (Array.isArray(rawItems) ? rawItems : []).filter(it => it && typeof it === 'object');

Type guard

const isHotelRow = (it) => it !== null && typeof it === 'object' && typeof (it.name ?? it.url ?? '') !== 'undefined';

Try / catch

try {
  return await booking.search(params);
} catch (e) {
  if (/malformed hotel row/.test(e.message)) {
    await sleep(2000);
    return booking.search(params); // lazy-load race often resolves on retry
  }
  throw e;
}

Prevention

When it happens

Trigger: raw.items is an array but contains a null/undefined entry or a primitive — e.g. the extractor pushed a placeholder/falsy value, or a DOM change made its row-parser return undefined for some cards.

Common situations: Partially rendered page where some cards lacked expected structure and the extractor appended null; a custom/patched extractor with inconsistent row parsing; DOM updates mid-extraction (lazy-load race) producing incomplete rows; site A/B tests changing card markup for a subset of results.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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