jackwener/OpenCLI · error · CommandExecutionError

Booking.com extractor returned malformed items

Error message

Booking.com extractor returned malformed items

What it means

This CommandExecutionError is thrown when the extractor reported ok:true but raw.items is not an array. The library expects the extractor to always return its results as an array; any other type means the payload is malformed and processing individual hotel rows cannot proceed safely.

Source

Thrown at clis/booking/search.js:291

    } catch (err) {
      throw new CommandExecutionError(`Failed to extract Booking.com cards: ${err?.message || err}`);
    }

    if (raw && typeof raw === 'object' && raw.data && raw.session) {
      raw = raw.data;
    }
    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.',
      );
    }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Update the library — a DOM change usually breaks both items collection and this check together.
  2. Log/inspect raw.items to see its actual type and value.
  3. Retry the search in case the page was in a transitional state during extraction.
  4. If using a custom extractor, ensure items is always an array (default to [] when nothing matches).

Example fix

// before (custom extractor)
return { ok: true, items: cards.map(parse) };
// after
const cards = [...document.querySelectorAll('[data-testid=property-card]')];
return { ok: true, items: (cards || []).map(parse) };
Defensive patterns

Strategy: validation

Validate before calling

// sanity-check that a search is expected to return items before calling
if (!destination || !checkin || !checkout) throw new Error('destination and dates are required for a results-bearing search');

Type guard

const hasItemsArray = (raw) => raw != null && typeof raw === 'object' && raw.ok === true && Array.isArray(raw.items);

Try / catch

try {
  return await booking.search(params);
} catch (e) {
  if (/malformed items/.test(e.message)) {
    await sleep(2000);
    return booking.search(params); // transient extraction state
  }
  throw e;
}

Prevention

When it happens

Trigger: The extractor returned an object with ok:true but items missing, null, or a non-array (e.g. an object map or undefined because its internal querySelectorAll matched nothing and it forgot to default to []).

Common situations: Booking.com DOM change broke the card-collection selector so the extractor never built the items array; extractor version mismatch after a library or site update; a custom extractor returning results in a different shape.

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/a2c8ab93f3653e2d. Report an issue: GitHub.