{"record":{"id":"aba73f5daf105768","repo":"jackwener/OpenCLI","slug":"no-prices-returned-for-train-no-trainno-froms","errorCode":null,"errorMessage":"No prices returned for train_no=${trainNo} ${fromStation.name} -> ${toStation.name} on ${date}","messagePattern":"No prices returned for train_no=(.+?) (.+?) -> (.+?) on (.+?)","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"warning","filePath":"clis/12306/price.js","lineNumber":157,"sourceCode":"        const seatTypes = String(kwargs['seat-types'] ?? '').trim() || 'OM9PA1A3A4FWZ';\n        if (!SEAT_TYPES_RE.test(seatTypes)) {\n            throw new ArgumentError('--seat-types must contain only 12306 seat letters/digits (A-Z, 0-9)');\n        }\n\n        const stations = await fetchStationBundle();\n        const fromStation = resolveStation(stations, fromArg);\n        const toStation = resolveStation(stations, toArg);\n        if (fromStation.code === toStation.code) {\n            throw new ArgumentError(`--from and --to must differ; both resolved to ${fromStation.name} (${fromStation.code})`);\n        }\n\n        const cookieHeader = await mintSession();\n        const stops = await queryStopsForPrice(cookieHeader, trainNo, fromStation.code, toStation.code, date);\n        const { fromNo, toNo } = pickStationNos(stops, fromStation.code, toStation.code, fromStation.name, toStation.name);\n        const priceData = await queryPrice(cookieHeader, trainNo, fromNo, toNo, seatTypes, date);\n        const rows = parsePriceData(priceData);\n        if (rows.length === 0) {\n            throw new EmptyResultError(\n                `No prices returned for train_no=${trainNo} ${fromStation.name} -> ${toStation.name} on ${date}`,\n                'Try a different seat-types letter set, or check that this train operates on the date.',\n            );\n        }\n        return rows;\n    },\n});\n\nexport const __test__ = { parsePriceData, pickStationNos, queryStopsForPrice, queryPrice, SEAT_LETTERS, TRAIN_NO_RE };\n","sourceCodeStart":139,"sourceCodeEnd":167,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/12306/price.js#L139-L167","documentation":"This EmptyResultError is thrown when the 12306 queryTicketPrice API responds successfully but parsePriceData yields zero price rows for the requested train_no/segment/date — i.e. 12306 has no price data to return. The library raises it instead of returning an empty list so callers can distinguish 'no data' from 'empty table'.","triggerScenarios":"Querying a train that does not operate on the given date; a train_no/segment combination with no on-sale inventory; a --seat-types letter set that matches no seats on that train; dates beyond the 12306 booking window (~15 days).","commonSituations":"Querying schedules published but not yet priced; holiday-schedule trains on off days; tickets sold out at every class so the price map is empty; typos in the date (--date 2025-13-40 style issues caught earlier, but a valid wrong date like last year is not).","solutions":["Retry with a different --seat-types letter set (or omit it to use the default OM9PA1A3A4FWZ).","Confirm the train operates on the date: run `12306 trains --from ... --to ...` for the same date.","Pick a date within the 12306 pre-sale window (usually ~15 days ahead).","Re-fetch train_no via `12306 trains` — internal train_no values are date-specific and can differ."],"exampleFix":"// before\n12306 price --train-no 24000000G10L --from 北京南 --to 上海 --date 2024-01-01 --seat-types A9\n// after\n12306 price --train-no 24000000G10L --from 北京南 --to 上海 --date 2026-09-01   # default seat-types, in-sale date","handlingStrategy":"fallback","validationCode":"const d = new Date(date);\nif (Number.isNaN(d.getTime()) || d < new Date() || d > Date.now() + 15 * 86400e3) {\n  console.warn(`date ${date} is in the past or beyond the ~15-day pre-sale window; prices may be empty`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  rows = await price({ 'train-no': tn, from, to, date });\n} catch (e) {\n  if (e instanceof EmptyResultError && /No prices returned/.test(e.message)) {\n    // fallback: retry with default seat-types and/or verify the train runs that day\n    rows = await price({ 'train-no': tn, from, to, date, 'seat-types': 'OM9PA1A3A4FWZ' });\n  } else throw e;\n}","preventionTips":["Confirm the train operates on the date via `12306 trains` before querying prices.","Stay within the ~15-day 12306 pre-sale window.","Re-fetch train_no for the specific date — internal train_no is date-dependent.","Treat EmptyResultError as 'no data', not a bug; catch it explicitly."],"tags":["empty-result","upstream-api","cli"],"backgroundTag":"empty-result-set","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}