{"record":{"id":"210d512decc0dea6","repo":"jackwener/OpenCLI","slug":"trip-com-is-asking-for-a-verification-complete-it-210d51","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/deals.js","lineNumber":39,"sourceCode":"    strategy: Strategy.COOKIE,\n    browser: true,\n    navigateBefore: false,\n    args: [\n        { name: 'limit', type: 'int', default: 20, help: 'Number of deals (1-50)' },\n    ],\n    columns: [\n        'rank',\n        'title', 'offer',\n        'discount',\n        'url',\n    ],\n    func: async (page, kwargs) => {\n        const limit = parseListLimit(kwargs.limit);\n\n        await page.goto(buildDealsUrl());\n        const waitResult = await page.evaluate(WAIT_FOR_DEALS_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 deals page did not render deal tiles (state=${String(waitResult)})`);\n        }\n        const raw = await page.evaluate(buildDealsExtractJs());\n        if (!Array.isArray(raw)) {\n            throw new CommandExecutionError('Trip.com deals DOM extraction returned malformed rows');\n        }\n        // The Top Deals hub is a permanent curated page, so once the wait confirms it\n        // rendered, zero parsed tiles means the tile markup drifted, not an empty hub.\n        if (raw.length === 0) {\n            throw new CommandExecutionError('Trip.com deals hub rendered but no promotion tiles parsed (the tile markup may have changed)');\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            title: r.title,\n            offer: r.offer,\n            discount: r.discount,","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/deals.js#L21-L57","documentation":"AuthRequiredError thrown when the Trip.com deals page's wait probe reports state 'captcha': Trip.com served a bot-detection/verification challenge instead of the Top Deals content. The library surfaces this so the user can complete the challenge in their own authenticated browser session rather than having the automation fight it.","triggerScenarios":"Calling the Trip.com deals command; page.evaluate(WAIT_FOR_DEALS_JS) resolves with 'captcha' after page.goto(buildDealsUrl()), typically because Trip.com flagged the automated session.","commonSituations":"Running from a datacenter/VPN IP; too-frequent scraping from one session; missing or expired session cookies; new browser profile without prior Trip.com trust; Trip.com throttling during high traffic.","solutions":["Open the Trip.com browser session manually, complete the verification challenge, then rerun the command","Slow down request frequency or wait before retrying so rate-limit signals decay","Use a residential IP / disable VPN or datacenter proxy","Refresh the session cookies in the browser session and retry"],"exampleFix":"// before (hard retry loop that keeps hitting the challenge)\nfor (;;) { await runTripDeals(); }\n// after\ntry {\n    await runTripDeals();\n} catch (e) {\n    if (e instanceof AuthRequiredError) {\n        console.error('Complete the Trip.com verification in your browser session, then retry.');\n    } else { throw e; }\n}","handlingStrategy":"retry","validationCode":"// Probe for a challenge before running the extract\nconst isChallenge = await page.evaluate(() =>\n    !!document.querySelector('iframe[src*=captcha], [class*=verify], #challenge'));\nif (isChallenge) console.error('Solve the Trip.com verification in your browser session first');","typeGuard":"function isAuthRequired(e) {\n    return e instanceof AuthRequiredError || (e && e.name === 'AuthRequiredError');\n}","tryCatchPattern":"try {\n    await runTripDeals();\n} catch (e) {\n    if (isAuthRequired(e)) {\n        // pause, prompt user to complete verification in browser session, then retry with backoff\n    } else { throw e; }\n}","preventionTips":["Warm up the browser session (visit trip.com normally) before automated calls","Avoid datacenter IPs / VPNs; prefer residential egress","Throttle request frequency and add jitter between runs"],"tags":["captcha","auth-required","bot-detection","trip-com"],"backgroundTag":"captcha-challenge-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}