{"record":{"id":"8c969715eccc99be","repo":"jackwener/OpenCLI","slug":"from-and-to-must-differ-got-fromcode","errorCode":null,"errorMessage":"--from and --to must differ (got ${fromCode})","messagePattern":"--from and --to must differ \\(got (.+?)\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/ctrip/flight-round.js","lineNumber":69,"sourceCode":"        { name: 'from', required: true, positional: true, help: 'Departure IATA code (e.g. BJS / PEK)' },\n        { name: 'to', required: true, positional: true, help: 'Arrival IATA code (e.g. SHA / PVG)' },\n        { name: 'depart', required: true, help: 'Outbound date (YYYY-MM-DD)' },\n        { name: 'return', required: true, help: 'Return date (YYYY-MM-DD), on or after depart' },\n        { name: 'limit', default: 20, help: 'Number of flights (1-50)' },\n    ],\n    columns: [\n        'rank',\n        'airline', 'flightNo', 'aircraft',\n        'departureTime', 'departureAirport',\n        'arrivalTime', 'arrivalAirport', 'terminal',\n        'price', 'currency', 'cabin',\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 depart = parseIsoDate('depart', kwargs.depart);\n        const ret = parseIsoDate('return', kwargs.return);\n        if (ret < depart) {\n            throw new ArgumentError(`--return (${ret}) must be on or after --depart (${depart})`);\n        }\n        const limit = parseListLimit(kwargs.limit);\n\n        const searchUrl =\n            `https://flights.ctrip.com/online/list/round-${fromCode.toLowerCase()}-${toCode.toLowerCase()}` +\n            `?depdate=${depart}_${ret}&cabin=Y_S_C_F&adult=1&child=0&infant=0`;\n        await page.goto(searchUrl);\n        const waitResult = await page.evaluate(WAIT_FOR_FLIGHTS_ROUND_JS);\n        if (waitResult === 'captcha') {\n            throw new AuthRequiredError('flights.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');\n        }\n        if (waitResult !== 'content') {\n            throw new CommandExecutionError(`Ctrip round-trip flight page did not render flight cards (state=${String(waitResult)})`);","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/ctrip/flight-round.js#L51-L87","documentation":"An ArgumentError raised by the ctrip flight-round CLI argument validation: the parsed --from and --from IATA codes are identical, which would make a round-trip search nonsensical (Ctrip rejects same-origin round trips). parseIataCode normalizes both values before comparing, so 'PEK' vs 'pek' still matches and throws.","triggerScenarios":"Calling the flight-round command where kwargs.from and kwargs.to resolve to the same 3-letter IATA code, e.g. `--from PEK --to PEK` or `--from pek --to PEK`.","commonSituations":"Programmatic loop building routes where origin/destination variables were accidentally set from the same field; default values filled in for both flags; copy-paste mistakes in shell scripts.","solutions":["Pass distinct origin and destination IATA codes for --from and --to.","If building calls programmatically, validate fromCode !== toCode before invoking the CLI.","Check for swapped or duplicated variables feeding the two flags in your script."],"exampleFix":"// before\nrun(['flight-round', '--from', origin, '--to', origin, '--depart', d, '--return', r]);\n// after\nif (origin === destination) throw new Error('origin and destination must differ');\nrun(['flight-round', '--from', origin, '--to', destination, '--depart', d, '--return', r]);","handlingStrategy":"validation","validationCode":"const iata = (s) => String(s || '').trim().toUpperCase();\nif (iata(from) === iata(to)) throw new Error('origin and destination IATA codes must differ');","typeGuard":"function isDistinctRoute(from, to) { return String(from).trim().toUpperCase() !== String(to).trim().toUpperCase(); }","tryCatchPattern":"try { await cli(['flight-round', args]); } catch (e) { if (e instanceof ArgumentError) { console.error('usage:', e.message); process.exitCode = 2; } else throw e; }","preventionTips":["Validate origin !== destination before invoking flight-round.","Normalize IATA codes (trim + uppercase) in your own input pipeline.","Avoid defaulting both --from and --to from the same config field.","Use the ARGUMENT exit code to distinguish usage bugs from runtime failures in CI."],"tags":["argument-validation","input-error","ctrip","cli"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}