{"record":{"id":"a6dac29b810c496f","repo":"jackwener/OpenCLI","slug":"trip-com-flight-page-did-not-render-flight-cards","errorCode":null,"errorMessage":"Trip.com flight page did not render flight cards (state=${String(waitResult)})","messagePattern":"Trip\\.com flight page did not render flight cards \\(state=(.+?)\\)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/trip/flight-round.js","lineNumber":65,"sourceCode":"        const toCode = parseIataCode('to', kwargs.to);\n        if (fromCode === toCode) {\n            throw new ArgumentError(`--from and --to must differ (got ${fromCode})`);\n        }\n        const depart = parseIsoDate('depart', kwargs.depart);\n        const ret = parseIsoDate('return', kwargs.return);\n        if (depart >= ret) {\n            throw new ArgumentError(`--depart must be before --return (got ${depart} .. ${ret})`);\n        }\n        const limit = parseListLimit(kwargs.limit);\n\n        const searchUrl = buildFlightRoundSearchUrl(fromCode, toCode, depart, ret);\n        await page.goto(searchUrl);\n        const waitResult = await page.evaluate(WAIT_FOR_FLIGHTS_JS);\n        if (waitResult === 'captcha') {\n            throw new AuthRequiredError('trip.com', 'Trip.com is asking for a verification; complete it in your browser session and retry');\n        }\n        if (waitResult !== 'content') {\n            throw new CommandExecutionError(`Trip.com flight page did not render flight cards (state=${String(waitResult)})`);\n        }\n        const raw = await page.evaluate(buildFlightExtractJs());\n        if (!Array.isArray(raw)) {\n            const reason = raw && typeof raw === 'object' && typeof raw.error === 'string'\n                && /^malformed flight card \\d+: [a-z /]+$/.test(raw.error)\n                ? `: ${raw.error}`\n                : '';\n            throw new CommandExecutionError(`Trip.com flight DOM extraction returned malformed rows${reason}`);\n        }\n        if (raw.length === 0) {\n            throw new EmptyResultError('trip flight-round', `No round-trip flights for ${fromCode} to ${toCode} on ${depart} .. ${ret}`);\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            airline: r.airline,\n            departureTime: r.departureTime,\n            departureAirport: r.departureAirport,\n            arrivalTime: r.arrivalTime,","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/flight-round.js#L47-L83","documentation":"CommandExecutionError thrown when the flight search page loaded but WAIT_FOR_FLIGHTS_JS resolved with a state that is neither 'content' nor 'captcha' (e.g. a timeout state): the flight cards never rendered, so extraction cannot proceed. The failing state is embedded in the message for diagnosis.","triggerScenarios":"Calling flight-round with valid arguments, but after goto the flight-card wait selector never matches within its budget — page.evaluate(WAIT_FOR_FLIGHTS_JS) returns e.g. 'timeout', producing (state=timeout) in the message.","commonSituations":"Slow page loads on complex search results; Trip.com returning an intermediate 'searching' page that never transitions; layout changes renaming flight-card containers; heavy regional variants without the expected cards.","solutions":["Retry the search — transient render timeouts commonly succeed on a second attempt","Check the embedded state value and increase wait budget/patience if it is a timeout","Confirm manually in the browser session that results render for the same route/dates","If persistent, update WAIT_FOR_FLIGHTS_JS selectors to the current Trip.com card markup"],"exampleFix":"// before\nconst waitResult = await page.evaluate(WAIT_FOR_FLIGHTS_JS);\nif (waitResult !== 'content') { throw ... }\n// after\nconst waitResult = await page.evaluate(WAIT_FOR_FLIGHTS_JS);\nif (waitResult !== 'content' && waitResult !== 'captcha') {\n    await page.waitForTimeout(3000);\n    const retryResult = await page.evaluate(WAIT_FOR_FLIGHTS_JS);\n    if (retryResult === 'content') { /* proceed */ }\n}","handlingStrategy":"retry","validationCode":"// Check flight-card containers exist before relying on the wait result\nconst cards = await page.evaluate(() =>\n    document.querySelectorAll('[class*=flight-card], [data-flight-id]').length);\nif (cards === 0) console.warn('No flight-card nodes yet; results may still be loading');","typeGuard":"function isWaitState(v) {\n    return typeof v === 'string' && ['content', 'captcha', 'timeout', 'empty'].includes(v);\n}","tryCatchPattern":"try {\n    await runFlightRound(args);\n} catch (e) {\n    if (e instanceof CommandExecutionError && /did not render flight cards/.test(e.message)) {\n        // parse state from message; retry with longer budget or surface a slow-page warning\n    } else { throw e; }\n}","preventionTips":["Retry render timeouts once with backoff before failing","Budget generous wait time for long-haul multi-leg searches","CI-check flight-card selectors against saved result-page HTML"],"tags":["scraping","page-load-timeout","dom-parsing","trip-com"],"backgroundTag":"page-render-timeout","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}