jackwener/OpenCLI · warning · EmptyResultError

No sailings for ${fromCity} to ${toCity} on ${date}

Error message

No sailings for ${fromCity} to ${toCity} on ${date}

What it means

This is thrown as an EmptyResultError by the Ctrip ferry CLI when DOM scraping completed successfully but the parsed sailing-rows array is empty. The library distinguishes a genuine 'no sailings' result from a parse failure: if cards were rendered but rows could not be parsed, a different CommandExecutionError is thrown instead, so this error means the page genuinely listed zero sailings for the requested city pair and date.

Source

Thrown at clis/ctrip/ferry.js:72

        const searchUrl = buildFerryListUrl(fromCity, toCity, date);
        await page.goto(searchUrl);
        const waitResult = await page.evaluate(WAIT_FOR_FERRY_JS);
        if (waitResult === 'captcha') {
            throw new AuthRequiredError('ship.ctrip.com', 'Ctrip is asking for a captcha; complete it in your browser session and retry');
        }
        if (waitResult !== 'content') {
            throw new CommandExecutionError(`Ctrip ferry page did not render sailing rows (state=${String(waitResult)})`);
        }
        const renderedCardCount = await page.evaluate(buildScrollUntilJs('.list-item-parent', limit));
        const raw = await page.evaluate(buildFerryExtractJs());
        if (!Array.isArray(raw)) {
            throw new CommandExecutionError('Ctrip ferry DOM extraction returned malformed rows');
        }
        if (raw.length === 0) {
            if (Number(renderedCardCount) > 0) {
                throw new CommandExecutionError('Ctrip ferry rows rendered but parser did not find required sailing anchors');
            }
            throw new EmptyResultError('ctrip ferry', `No sailings for ${fromCity} to ${toCity} on ${date}`);
        }
        return raw.slice(0, limit).map((r, i) => ({
            rank: i + 1,
            shipName: r.shipName,
            departureTime: r.departureTime,
            fromPort: r.fromPort,
            arrivalTime: r.arrivalTime,
            toPort: r.toPort,
            duration: r.duration,
            price: r.price,
            status: r.status,
            url: searchUrl,
        }));
    },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Double-check the city names and confirm the route is actually served by a ferry on that date on the Ctrip site.
  2. Retry with a nearby date to confirm availability is the issue rather than a route/data problem.
  3. Catch EmptyResultError in your script and treat it as an expected empty result (exit code EMPTY_RESULT), not a crash.
  4. If sailings clearly exist on the site, report a possible DOM/parser drift issue to the maintainers.

Example fix

// before
cli(['ferry', '--from', 'Shanghai', '--to', 'Shengsi', '--date', '2026-01-05']);
// after
try {
  cli(['ferry', '--from', 'Shanghai', '--to', 'Shengsi', '--date', '2026-01-05']);
} catch (e) {
  if (e instanceof EmptyResultError) console.log('no sailings that day');
  else throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

const valid = from && to && /^\d{4}-\d{2}-\d{2}$/.test(date) && new Date(date) >= new Date(new Date().toDateString());
if (!valid) throw new Error('check route/city names and use a current-or-future date');

Type guard

function isEmptyResultError(e) { return e && typeof e.code === 'string' && e.code === 'EMPTY_RESULT'; }

Try / catch

try { const sailings = await cli(['ferry','--from',from,'--to',to,'--date',date]); return sailings; }
catch (e) { if (e instanceof EmptyResultError || e.code === 'EMPTY_RESULT') return []; throw e; }

Prevention

When it happens

Trigger: Running the `ctrip ferry` command with a from/to city pair and date on which Ctrip's ferry search page renders zero sailing cards, and renderedCardCount is 0 (or falsy) so the empty result is legitimate.

Common situations: Searching an off-season date or a route that is suspended; misspelling city names so Ctrip resolves no routes; querying a same-day date after all sailings have departed; picking a route Ctrip does not sell (e.g. ferry vs. bus substituted).

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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