{"record":{"id":"a74dff42c70fc239","repo":"jackwener/OpenCLI","slug":"booking-com-page-returned-no-extractable-data","errorCode":null,"errorMessage":"Booking.com page returned no extractable data","messagePattern":"Booking\\.com page returned no extractable data","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/booking/search.js","lineNumber":281,"sourceCode":"    // Booking lazy-loads price cells; wait for at least the first card price to settle.\n    try {\n      await page.wait('selector', '[data-testid=property-card]', { timeoutMs: 20000 });\n    } catch (_) {\n      // selector wait is best-effort — extractor handles empty case explicitly\n    }\n\n    let raw;\n    try {\n      raw = await page.evaluate(EXTRACTOR);\n    } catch (err) {\n      throw new CommandExecutionError(`Failed to extract Booking.com cards: ${err?.message || err}`);\n    }\n\n    if (raw && typeof raw === 'object' && raw.data && raw.session) {\n      raw = raw.data;\n    }\n    if (!raw || typeof raw !== 'object') {\n      throw new CommandExecutionError('Booking.com page returned no extractable data');\n    }\n    if (raw.blocked) {\n      throw new CommandExecutionError('Booking.com served a verification / captcha page; retry later or change profile');\n    }\n\n    if (raw.ok !== true) {\n      throw new CommandExecutionError('Booking.com extractor returned an invalid status');\n    }\n    if (!Array.isArray(raw.items)) {\n      throw new CommandExecutionError('Booking.com extractor returned malformed items');\n    }\n\n    const items = raw.items;\n    if (items.length === 0) {\n      const totalText = String(raw.totalText || '').trim();\n      if (hasPositiveResultCount(totalText)) {\n        throw new CommandExecutionError(\n          `Booking.com page declared results but no property cards were parsed: ${totalText}`,","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/booking/search.js#L263-L299","documentation":"This CommandExecutionError is thrown when page.evaluate(EXTRACTOR) returned a value that is not a usable object (null, undefined, or a non-object). It means the extractor ran but produced nothing the command can process. It is a distinct failure from extraction throwing: the script completed but its result was empty or of the wrong shape.","triggerScenarios":"The extractor returned null/undefined or a primitive — e.g. the selector found no nodes and the extractor short-circuited, or an enveloped result {data, session} unwrapped to nothing.","commonSituations":"Booking.com served an empty or skeleton shell page (no results markup) so the extractor bailed; a soft bot-block page with HTTP 200 returned no data; an intermediate/redirect page was captured instead of results; extractor version mismatch after a site update.","solutions":["Retry with a different destination/dates or later — the page may have rendered no content.","Load the search URL in a normal browser to confirm results actually render.","Change browser profile / user agent if the site is serving bot-detection shells.","Update the library if Booking.com changed its page structure.","Add logging of the raw return value to see exactly what the extractor produced."],"exampleFix":"// before\nconst raw = await page.evaluate(EXTRACTOR);\nif (!raw || typeof raw !== 'object') throw new Error('no data');\n// after\nconst raw = await page.evaluate(EXTRACTOR);\nconsole.error('extractor returned:', raw); // diagnose before failing\nif (!raw || typeof raw !== 'object') throw new Error('no data');","handlingStrategy":"fallback","validationCode":"// validate inputs are likely to produce a rendered results page\nif (!destination || String(destination).trim().length < 2) throw new Error('destination too short to yield results');","typeGuard":null,"tryCatchPattern":"try {\n  return await booking.search(params);\n} catch (e) {\n  if (/no extractable data/.test(e.message)) {\n    return fallbackSearchProvider(params); // alternate scraper or API\n  }\n  throw e;\n}","preventionTips":["Retry once before giving up — shell pages are often transient.","Use a realistic browser profile/user agent to avoid bot-shell responses.","Confirm the URL renders in a normal browser when debugging.","Keep the library updated for Booking.com structural changes.","Have a secondary data source configured for critical workflows."],"tags":["scraping","browser-automation","empty-response"],"backgroundTag":"dom-extraction-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}