jackwener/OpenCLI · error · ArgumentError

<to> station must not be empty

Error message

<to> station must not be empty

What it means

ArgumentError thrown by the 12306 trains command when the positional `to` argument is missing, null, or whitespace-only after trimming. The destination station is required to form the leftTicket query, so it is validated immediately after `from` and before any network requests.

Source

Thrown at clis/12306/trains.js:126

    domain: 'kyfw.12306.cn',
    strategy: Strategy.PUBLIC,
    browser: false,
    args: [
        { name: 'from', positional: true, required: true, help: 'Origin station: Chinese name (北京), telecode (BJP), or pinyin (beijing)' },
        { name: 'to', positional: true, required: true, help: 'Destination station: same forms as <from>' },
        { name: 'date', required: true, help: 'Departure date in YYYY-MM-DD' },
        { name: 'limit', type: 'int', default: 50, help: `Maximum rows (1-${MAX_LIMIT})` },
    ],
    columns: [
        'code', 'from_station', 'to_station', 'start_time', 'arrive_time',
        'duration', 'available', 'business_seat', 'first_seat', 'second_seat',
        'soft_sleeper', 'hard_sleeper', 'hard_seat', 'no_seat', 'train_no',
    ],
    func: async (kwargs) => {
        const fromArg = String(kwargs.from ?? '').trim();
        const toArg = String(kwargs.to ?? '').trim();
        if (!fromArg) throw new ArgumentError('<from> station must not be empty');
        if (!toArg) throw new ArgumentError('<to> station must not be empty');
        const date = validateDate(kwargs.date);
        const limit = normalizeLimit(kwargs.limit, 50, MAX_LIMIT);

        const stations = await fetchStationBundle();
        const fromStation = resolveStation(stations, fromArg);
        const toStation = resolveStation(stations, toArg);
        if (fromStation.code === toStation.code) {
            throw new ArgumentError(`<from> and <to> must differ; both resolved to ${fromStation.name} (${fromStation.code})`);
        }
        const stationByCode = new Map(stations.map((s) => [s.code, s]));

        const cookieHeader = await mintSession();
        const rawRows = await queryLeftTickets(cookieHeader, fromStation.code, toStation.code, date);
        const decoded = rawRows
            .map((line) => parseTrainRecord(decodeURIComponent(line.replace(/%0A/g, '')), stationByCode))
            .filter(Boolean);

        if (decoded.length === 0) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Provide a non-empty destination station: Chinese name (上海虹桥), telecode (AOH), or pinyin (shanghaihongqiao).
  2. Check argument order — from, to, then date; a missing positional shifts everything left.
  3. In scripts, validate the destination variable before invoking.
  4. Quote station names that may contain spaces.

Example fix

// before
const args = [origin, dest, date]; // dest may be ''
await trains(...args);
// after
if (!dest?.trim()) throw new Error('destination station required');
const args = [origin, dest, date];
await trains(...args);
Defensive patterns

Strategy: validation

Validate before calling

if (!to || !String(to).trim()) {
  throw new Error('destination station is required: Chinese name, telecode, or pinyin');
}

Type guard

function isNonEmptyString(v) {
  return typeof v === 'string' && v.trim().length > 0;
}

Try / catch

try {
  await trains({ from, to, date });
} catch (e) {
  if (e.name === 'ArgumentError' && /<to> station must not be empty/.test(e.message)) {
    console.error('Destination missing. Usage: trains <from> <to> <YYYY-MM-DD>');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the trains command with `to` undefined, empty string, or whitespace only — e.g. `trains 北京 "" 2026-09-01`, or programmatic invocation with `kwargs.to` null.

Common situations: Forgot to fill the destination placeholder in a copied command; destination variable unset in a script; positional argument reordered so the destination lands in the date slot; piping output where the second field is blank.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/29f11e940f5972df. Report an issue: GitHub.