{"record":{"id":"1135a36d9264cf47","repo":"jackwener/OpenCLI","slug":"vacations-ctrip-com","errorCode":null,"errorMessage":"vacations.ctrip.com","messagePattern":"vacations\\.ctrip\\.com","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/package.js","lineNumber":47,"sourceCode":"        { name: 'destination', required: true, positional: true, help: 'Destination keyword (e.g. 三亚 / 北京 / 曼谷)' },\n        { name: 'limit', default: 20, help: 'Number of packages (1-50)' },\n    ],\n    columns: [\n        'rank',\n        'title', 'subtitle',\n        'tags', 'score', 'sold', 'reviews',\n        'price',\n        'url',\n    ],\n    func: async (page, kwargs) => {\n        const destination = parsePlaceName('destination', kwargs.destination);\n        const limit = parseListLimit(kwargs.limit);\n\n        const searchUrl = buildPackageListUrl(destination);\n        await page.goto(searchUrl);\n        const waitResult = await page.evaluate(WAIT_FOR_VACATIONS_JS);\n        if (waitResult === 'captcha') {\n            throw new AuthRequiredError('vacations.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');\n        }\n        if (waitResult === 'empty') {\n            throw new EmptyResultError('ctrip package', `No flight-plus-hotel packages for \"${destination}\"`);\n        }\n        if (waitResult !== 'content') {\n            throw new CommandExecutionError(`Ctrip package page did not render package cards (state=${String(waitResult)})`);\n        }\n        const raw = await page.evaluate(buildVacationsExtractJs());\n        if (!Array.isArray(raw)) {\n            throw new CommandExecutionError('Ctrip package DOM extraction returned malformed rows');\n        }\n        if (raw.length === 0) {\n            throw new CommandExecutionError('Ctrip package cards rendered but parser did not find required package anchors');\n        }\n        return raw.slice(0, limit).map((r, i) => ({\n            rank: i + 1,\n            title: r.title,\n            subtitle: r.subtitle,","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/package.js#L29-L65","documentation":"AuthRequiredError thrown when the Ctrip vacations (flight+hotel package) page presents a captcha. WAIT_FOR_VACATIONS_JS returns 'captcha' and the library requires the user to solve it in their browser session before package search can proceed. Automatic retries will keep failing until the captcha is cleared.","triggerScenarios":"page.evaluate(WAIT_FOR_VACATIONS_JS) resolves 'captcha' after page.goto(buildPackageListUrl(destination)) — anti-bot detection triggered by automation, blocked IP, or stale session cookies on vacations.ctrip.com.","commonSituations":"Rapid repeated package searches from a server IP; first-time access from a new region/IP; expired connect session; headless browsing fingerprint detected.","solutions":["Solve the captcha in the interactive browser session, then re-run the command","Re-authenticate/refresh the CLI's browser profile cookies","Throttle request frequency and add jittered delays","Use a residential IP or rotate network exit"],"exampleFix":"// before\nawait ctrip.package({ destination: '三亚' }); // throws on captcha\n// after\ntry {\n  return await ctrip.package({ destination: '三亚' });\n} catch (e) {\n  if (e instanceof AuthRequiredError) {\n    await promptUserToSolveCaptchaInBrowser();\n    return await ctrip.package({ destination: '三亚' });\n  }\n  throw e;\n}","handlingStrategy":"retry","validationCode":"// cannot be validated pre-call; detect captcha state after load\nconst state = await page.evaluate(WAIT_FOR_VACATIONS_JS);\nif (state === 'captcha') await requireManualCaptchaResolution();","typeGuard":"const isAuthRequiredError = (e) => e instanceof AuthRequiredError || e?.name === 'AuthRequiredError';","tryCatchPattern":"try {\n  return await ctrip.package({ destination });\n} catch (e) {\n  if (isAuthRequiredError(e)) {\n    await promptUserToSolveCaptcha();\n    return await ctrip.package({ destination }); // retry once after manual solve\n  }\n  throw e;\n}","preventionTips":["Warm up the session by browsing vacations.ctrip.com manually first","Rate-limit package searches; add random delays","Rotate IPs / avoid obvious datacenter exits","Halt automation on repeated captcha states and alert an operator"],"tags":["captcha","anti-bot","auth","scraping"],"backgroundTag":"captcha-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}