{"record":{"id":"e238a033b56fb3bc","repo":"jackwener/OpenCLI","slug":"from-and-to-must-differ-both-resolved-to-de","errorCode":null,"errorMessage":"--from and --to must differ (both resolved to ${dest.name})","messagePattern":"--from and --to must differ \\(both resolved to (.+?)\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/trip/package.js","lineNumber":70,"sourceCode":"        const to = parseKeyword('to', kwargs.to);\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 adults = parseAdults(kwargs.adults);\n        const limit = parseListLimit(kwargs.limit);\n\n        const origin = await resolvePackageCity(from);\n        if (!origin) {\n            throw new ArgumentError(`Could not resolve origin \"${from}\" to a Trip.com city; run 'trip search ${from}' to find the name`);\n        }\n        const dest = await resolvePackageCity(to);\n        if (!dest) {\n            throw new ArgumentError(`Could not resolve destination \"${to}\" to a Trip.com city; run 'trip search ${to}' to find the name`);\n        }\n        if (origin.cityId === dest.cityId) {\n            throw new ArgumentError(`--from and --to must differ (both resolved to ${dest.name})`);\n        }\n\n        const groups = await fetchPackageSearch({\n            dcode: origin.cityCode,\n            acode: dest.cityCode,\n            hcityid: String(dest.cityId),\n            depart,\n            ret,\n            adults,\n        });\n        if (groups.length === 0) {\n            throw new EmptyResultError('trip package', `No flight+hotel packages for ${origin.name} to ${dest.name} on ${depart} .. ${ret}`);\n        }\n        const rows = groups\n            .filter((g) => g && Array.isArray(g.flightlist) && g.flightlist.length)\n            .map((g) => mapPackageRow(g, 0))\n            .filter((row) => row.flightNo && row.from && row.to && row.departure && row.arrival);\n        if (rows.length === 0) {","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/trip/package.js#L52-L88","documentation":"After both endpoints resolve, the library compares origin.cityId and dest.cityId and rejects searches where they are equal — Trip.com package (flight+hotel) searches require distinct origin and destination cities. The message helpfully shows the shared resolved city name.","triggerScenarios":"Passing --from and --to that normalize to the same Trip.com city, e.g. spelling variants ('NYC' and 'New York'), an alias and the canonical name, or genuinely identical values.","commonSituations":"Users specifying a metro area via two aliases, scripts echoing the same variable into both flags, or assuming nearby-but-distinct suburbs would resolve differently when both map to one cityId.","solutions":["Choose genuinely different origin and destination cities","Compare resolved city ids in your wrapper before invoking the CLI","Catch ArgumentError and show the user the merged city name so they can correct one endpoint","Note that distinct names are not enough — the underlying cityIds must differ"],"exampleFix":"// before\n--from \"NYC\" --to \"New York\" // both resolve to same cityId\n// after\n--from \"New York\" --to \"Boston\"","handlingStrategy":"validation","validationCode":"const origin = await resolvePackageCity(from);\nconst dest = await resolvePackageCity(to);\nif (origin && dest && origin.cityId === dest.cityId) {\n  throw new Error(`--from and --to both resolve to ${dest.name}; pick distinct cities`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await tripPackageSearch({ from, to });\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('must differ')) {\n    throw new UserInputError(`Both endpoints resolved to ${dest.name}; choose a different origin or destination`);\n  }\n  throw e;\n}","preventionTips":["Compare resolved cityIds (not raw strings) before searching — aliases collapse to one city","Never interpolate the same variable into both --from and --to","Educate users that name variants of one city are rejected","For same-city stays, use a hotel-only search instead of a package search"],"tags":["validation","cli","city-resolution","arguments","trip-com"],"backgroundTag":"invalid-cli-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}