jackwener/OpenCLI · error · CommandExecutionError

Failed to parse 12306 station_name.js: no station records fo

Error message

Failed to parse 12306 station_name.js: no station records found

What it means

CommandExecutionError from parseStationBundle when the extracted quoted string exists but splits into zero usable station records. Each record must have at least 8 `|`-separated fields including a telecode at position 2; if the string is present but empty or malformed, the stations array stays empty and this error is thrown.

Source

Thrown at clis/12306/utils.js:62

        throw new CommandExecutionError('Failed to parse 12306 station_name.js: source string not found');
    }
    const raw = match[1];
    const records = raw.split('@').filter(Boolean);
    const stations = [];
    for (const r of records) {
        const parts = r.split('|');
        if (parts.length < 8 || !parts[2]) continue;
        stations.push({
            short: parts[0] || '',
            name: parts[1] || '',
            code: parts[2] || '',
            pinyin: parts[3] || '',
            abbr: parts[4] || '',
            city: parts[7] || '',
        });
    }
    if (stations.length === 0) {
        throw new CommandExecutionError('Failed to parse 12306 station_name.js: no station records found');
    }
    return stations;
}

/**
 * Resolve a user-supplied station identifier to a telecode.
 *
 * Accepts Chinese name (`上海虹桥`), telecode (`AOH`), pinyin
 * (`shanghaihongqiao`), short alias (`shh`), or city name with a
 * preference for the city's main station.
 */
export function resolveStation(stations, input) {
    const trimmed = String(input ?? '').trim();
    if (!trimmed) throw new ArgumentError('station must not be empty');
    if (STATION_CODE_RE.test(trimmed)) {
        const exact = stations.find((s) => s.code === trimmed);
        if (exact) return exact;
        throw new ArgumentError(`Unknown 12306 station telecode "${trimmed}"`);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-fetch — a truncated or stub response is often transient; clear any intermediary cache/proxy.
  2. Dump the matched string (first ~200 chars) and verify records are `@`-separated with 8+ pipe fields.
  3. If 12306 changed the bundle layout, update the field positions and the parts.length/telecode guards in parseStationBundle.
  4. Pin or cache a known-good station bundle as a fallback.

Example fix

// before
if (stations.length === 0) {
    throw new CommandExecutionError('Failed to parse 12306 station_name.js: no station records found');
}
// after
if (stations.length === 0) {
    throw new CommandExecutionError(`Failed to parse 12306 station_name.js: no station records found (extracted ${raw.length} chars, sample: ${raw.slice(0, 100)})`);
}
Defensive patterns

Strategy: type-guard

Validate before calling

const match = text.match(/'([^']+)'/);
const records = match ? match[1].split('@').filter(Boolean) : [];
const ok = records.some((r) => r.split('|').length >= 8 && r.split('|')[2]);
if (!ok) console.warn('station bundle present but structurally empty/malformed');

Type guard

function hasValidStationRecords(text) {
  const m = typeof text === 'string' && text.match(/'([^']+)'/);
  if (!m) return false;
  return m[1].split('@').some((r) => {
    const p = r.split('|');
    return p.length >= 8 && Boolean(p[2]);
  });
}

Try / catch

try {
  const stations = await fetchStationBundle();
} catch (e) {
  if (/no station records found/.test(e.message)) {
    console.error('Bundle malformed/truncated — refetching or falling back to cached bundle');
    const stations = parseStationBundle(await fs.readFile('./station_name.cache.js', 'utf8'));
  } else throw e;
}

Prevention

When it happens

Trigger: station_name.js served a quoted but empty or structurally changed string — e.g. a stub file with `var station_names ='';`, a truncated download, or a 12306 format change that alters field positions/count so every record fails the `parts.length < 8 || !parts[2]` guard.

Common situations: CDN serving a truncated/cached placeholder file; 12306 mid-deploy serving a stub bundle; a protocol change in the bundle format (fewer fields per record); a proxy compressing/altering the body such that the quoted literal is mangled.

Understand the failure class

Related errors


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