{"record":{"id":"e1a6f06d70292185","repo":"jackwener/OpenCLI","slug":"trip-com-is-asking-for-a-verification-complete-it-e1a6f0","errorCode":null,"errorMessage":"Trip.com is asking for a verification; complete it in your browser session and retry","messagePattern":"Trip\\.com is asking for a verification; complete it in your browser session and retry","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/trip/flight.js","lineNumber":57,"sourceCode":"        'arrivalTime', 'arrivalAirport',\n        'duration', 'stops',\n        'price', 'currency',\n        'url',\n    ],\n    func: async (page, kwargs) => {\n        const fromCode = parseIataCode('from', kwargs.from);\n        const toCode = parseIataCode('to', kwargs.to);\n        if (fromCode === toCode) {\n            throw new ArgumentError(`--from and --to must differ (got ${fromCode})`);\n        }\n        const date = parseIsoDate('date', kwargs.date);\n        const limit = parseListLimit(kwargs.limit);\n\n        const searchUrl = buildFlightSearchUrl(fromCode, toCode, date);\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', `No flights for ${fromCode} to ${toCode} on ${date}`);\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            airline: r.airline,","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/flight.js#L39-L75","documentation":"This AuthRequiredError from clis/trip/flight.js is thrown when WAIT_FOR_FLIGHTS_JS, evaluated after page.goto(searchUrl), returns 'captcha', meaning Trip.com served a bot-verification challenge instead of flight content. The library surfaces it as an auth/session requirement: the shared browser session must pass human verification before scraping can proceed. It is not a code bug and retrying immediately without solving the challenge will fail again.","triggerScenarios":"page.evaluate(WAIT_FOR_FLIGHTS_JS) after navigating to the built flight search URL returns exactly 'captcha' — Trip.com presented a CAPTCHA/anti-bot interstitial instead of flight cards.","commonSituations":"Running many flight searches in quick succession from a datacenter or VPN IP; a browser profile with no prior Trip.com cookies; Trip.com tightening anti-bot rules; scraping during high-traffic periods.","solutions":["Open the same browser session interactively, complete the CAPTCHA, then rerun the command.","Reduce request frequency and add delays between searches to lower the bot score.","Use a residential IP / disable VPN or datacenter proxy for the browser session.","Reuse a warmed-up persistent browser profile with existing Trip.com cookies instead of a fresh profile."],"exampleFix":"// before\n// headless fresh profile, 50 rapid searches in a loop\n// after\n// reuse persistent profile, throttle to 1 search / few seconds,\n// and on AuthRequiredError pause and let the user solve the challenge\ntry {\n  await runTripFlight(args);\n} catch (e) {\n  if (e.name === 'AuthRequiredError') {\n    await openBrowserForManualVerification();\n    await runTripFlight(args);\n  } else throw e;\n}","handlingStrategy":"retry","validationCode":"// Pre-check not possible for server-side captcha; instead throttle before calling:\nawait sleep(2000 + Math.random() * 3000); // jitter between searches\nif (Date.now() - lastSearchAt < MIN_INTERVAL_MS) throw new Error('rate limit yourself');","typeGuard":"const isAuthRequired = (e) => e?.name === 'AuthRequiredError' || e instanceof AuthRequiredError;","tryCatchPattern":"try {\n  await runTripFlight(args);\n} catch (e) {\n  if (isAuthRequired(e)) {\n    await waitForManualCaptchaResolution(page); // user solves in browser\n    return runTripFlight(args); // single retry after verification\n  }\n  throw e;\n}","preventionTips":["Throttle and jitter automated searches.","Use a persistent cookie-warmed browser profile.","Avoid datacenter/VPN IPs for scraping sessions.","On AuthRequiredError, pause for human verification instead of retrying immediately."],"tags":["captcha","anti-bot","auth-required","trip-com","scraping"],"backgroundTag":"captcha-challenge","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}