jackwener/OpenCLI · error · CliError

HTTP_ERROR

HTTP_ERROR

Error message

`northbound failed: HTTP ${resp.status}`

What it means

After fetching https://push2.eastmoney.com/api/qt/kamtbs.rtmin/get, northbound.js checks resp.ok and throws this CliError with code HTTP_ERROR if the response status is not 2xx. It wraps the upstream HTTP status in the message so the developer knows the eastmoney endpoint rejected or failed the request.

Source

Thrown at clis/eastmoney/northbound.js:36

  args: [
    { name: 'direction', type: 'string', default: 'north', help: '方向:north (北向,即外资买A) / south (南向,即内地买港)' },
    { name: 'limit',     type: 'int',    default: 10,      help: '返回最近 N 分钟' },
  ],
  columns: ['time', 'cumulativeNetYi', 'minuteNetYi', 'totalNetYi'],
  func: async (args) => {
    const dir = String(args.direction ?? 'north').toLowerCase();
    if (!['north', 'south', 'n', 's'].includes(dir)) {
      throw new CliError('INVALID_ARGUMENT', `Unknown direction "${dir}". Valid: north / south`);
    }
    const limit = Math.max(1, Math.min(Number(args.limit) || 10, 240));

    const url = new URL('https://push2.eastmoney.com/api/qt/kamtbs.rtmin/get');
    url.searchParams.set('fields1', 'f1,f2,f3,f4');
    url.searchParams.set('fields2', 'f51,f52,f54,f56');
    url.searchParams.set('ut', 'b2884a393a59ad64002292a3e90d46a5');

    const resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
    if (!resp.ok) throw new CliError('HTTP_ERROR', `northbound failed: HTTP ${resp.status}`);
    const data = await resp.json();
    const key = (dir === 'south' || dir === 's') ? 's2n' : 'n2s';
    /** @type {string[]} */
    const rows = Array.isArray(data?.data?.[key]) ? data.data[key] : [];
    if (rows.length === 0) throw new CliError('NO_DATA', `No ${key} data returned`);

    // CSV fields per entry: "HH:MM,cumulative_net(万), minute_net(万), total_net(万)"
    // Drop rows with '-' (after market close or before open). Convert 万元 → 亿元 for readability.
    const valid = rows
      .map((r) => r.split(','))
      .filter((c) => c.length >= 4 && c[1] !== '-');
    if (valid.length === 0) {
      throw new CliError('NO_DATA', `${key} has no valid minute data yet (markets may not be open)`);
    }
    return valid.slice(-limit).map(([time, cum, min, total]) => ({
      time,
      cumulativeNetYi: +(Number(cum) / 10000).toFixed(4),
      minuteNetYi: +(Number(min) / 10000).toFixed(4),

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run the command after a short wait — transient 5xx and rate limits usually clear
  2. Check the HTTP status in the message: 403 suggests blocking/rate-limiting, 5xx suggests eastmoney-side trouble
  3. Slow down polling frequency and add backoff between calls
  4. Verify network/proxy access to push2.eastmoney.com (curl -I the URL)
  5. Check whether eastmoney changed the API path or ut token and update the URL in clis/eastmoney/northbound.js

Example fix

// before
const resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
// after — retry with backoff on transient failures
const resp = await fetchWithRetry(url, { headers: { 'User-Agent': 'Mozilla/5.0' } }, { retries: 3 });
Defensive patterns

Strategy: retry

Validate before calling

// Preflight connectivity check
const probe = await fetch('https://push2.eastmoney.com/api/qt/kamtbs.rtmin/get?fields1=f1&fields2=f51&ut=b2884a393a59ad64002292a3e90d46a5', { headers: { 'User-Agent': 'Mozilla/5.0' } });
if (!probe.ok) throw new Error(`eastmoney unreachable: HTTP ${probe.status}`);

Type guard

null

Try / catch

try {
  await runNorthbound(args);
} catch (e) {
  if (e.code === 'HTTP_ERROR' && /HTTP (5\d\d|429)/.test(e.message)) {
    await sleep(backoff); return runNorthbound(args); // retry transient failures
  }
  if (e.code === 'HTTP_ERROR' && /HTTP 403/.test(e.message)) console.error('Blocked/rate-limited by eastmoney; reduce frequency or change network.');
  else throw e;
}

Prevention

When it happens

Trigger: Any non-2xx response from push2.eastmoney.com when calling the northbound command — e.g. 403 from bot detection / rate limiting, 404 if the endpoint path changes, 5xx from eastmoney server-side issues, or a captive proxy returning an error page status.

Common situations: Eastmoney blocking datacenter IPs or aggressively rate-limiting repeated polling; running from a region or network where the request is intercepted; eastmoney temporarily changing/removing the API path or the 'ut' token becoming invalid; transient 5xx during high-traffic market hours.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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