jackwener/OpenCLI · error · CliError

HTTP_ERROR

HTTP_ERROR

Error message

`money-flow failed: HTTP ${resp.status}`

What it means

The eastmoney money-flow CLI throws CliError('HTTP_ERROR') when the push2.eastmoney.com capital-flow endpoint returns a non-OK HTTP status; the CLI skips JSON parsing since the body can't be trusted. The status code is embedded in the message to distinguish rate limiting (429/403, typical of eastmoney's WAF on unauthenticated ut-token traffic) from server-side errors (5xx).

Source

Thrown at clis/eastmoney/money-flow.js:60

      'f12', 'f14', 'f2', 'f3',
      range.fields.net, range.fields.netPct,
      range.fields.super, range.fields.big, range.fields.medium, range.fields.small,
    ];

    const url = new URL('https://push2.eastmoney.com/api/qt/clist/get');
    url.searchParams.set('pn', '1');
    url.searchParams.set('pz', String(limit));
    url.searchParams.set('po', po);
    url.searchParams.set('np', '1');
    url.searchParams.set('fltt', '2');
    url.searchParams.set('invt', '2');
    url.searchParams.set('fid', range.fid);
    url.searchParams.set('fs', A_MARKET);
    url.searchParams.set('fields', fieldList.join(','));
    url.searchParams.set('ut', 'b2884a393a59ad64002292a3e90d46a5');

    const resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
    if (!resp.ok) throw new CliError('HTTP_ERROR', `money-flow failed: HTTP ${resp.status}`);
    const data = await resp.json();
    const diff = Array.isArray(data?.data?.diff) ? data.data.diff : [];
    if (diff.length === 0) throw new CliError('NO_DATA', 'eastmoney returned no money-flow data');

    return diff.slice(0, limit).map((it, i) => ({
      rank: i + 1,
      code: it.f12,
      name: it.f14,
      price: it.f2,
      changePercent: it.f3,
      mainNet: it[range.fields.net],
      mainNetRatio: it[range.fields.netPct],
      superNet: it[range.fields.super],
      bigNet: it[range.fields.big],
      mediumNet: it[range.fields.medium],
      smallNet: it[range.fields.small],
    }));
  },

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the status in the message: 403/429 indicates throttling — add delays between requests and exponential backoff/retry.
  2. Verify the request works via curl with the same URL and User-Agent to isolate network/proxy issues from API issues.
  3. If consistently rejected, check whether the ut token or fs/fields parameters need updating to match the current push2 API contract.
  4. For 5xx, wait and retry — eastmoney outages are usually transient.
  5. Reduce polling frequency and cache results if you call this endpoint repeatedly.

Example fix

// before
const resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
if (!resp.ok) throw new CliError('HTTP_ERROR', `money-flow failed: HTTP ${resp.status}`);
// after — honor Retry-After on 429, retry transient failures
const resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
if (resp.status === 429) {
  const wait = Number(resp.headers.get('retry-after')) || 5;
  await new Promise((r) => setTimeout(r, wait * 1000));
}
if (!resp.ok) throw new CliError('HTTP_ERROR', `money-flow failed: HTTP ${resp.status}`);
Defensive patterns

Strategy: retry

Validate before calling

// Reachability pre-check before hitting the data endpoint
const probe = await fetch('https://push2.eastmoney.com', { headers: { 'User-Agent': 'Mozilla/5.0' } });
if (!probe.ok && (probe.status === 403 || probe.status === 429)) console.warn('eastmoney throttling detected; add delays before calling money-flow');

Type guard

function isCliError(e) { return e instanceof Error && 'code' in e; }
function isHttpError(e) { return isCliError(e) && e.code === 'HTTP_ERROR'; }

Try / catch

async function fetchMoneyFlowWithRetry(args, attempts = 3) {
  for (let i = 0; ; i++) {
    try { return await runMoneyFlow(args); }
    catch (err) {
      const retryable = err instanceof CliError && err.code === 'HTTP_ERROR' && /HTTP (429|5\d\d)/.test(err.message);
      if (!retryable || i >= attempts - 1) throw err;
      await new Promise((r) => setTimeout(r, 2000 * 2 ** i)); // exponential backoff
    }
  }
}

Prevention

When it happens

Trigger: Any fetch of the money-flow URL whose status is not 2xx: eastmoney rate-limiting or WAF-blocking the request, the hardcoded ut token becoming invalid, fs/fields/fid parameter combinations rejected after an API change, or transient 5xx from push2.eastmoney.com.

Common situations: Polling the endpoint in a loop or from CI triggering eastmoney's anti-scraping throttle; eastmoney rotating the shared ut token so requests get rejected; corporate/proxy environments stripping the User-Agent; persistent failures after eastmoney changes the clist API contract.

Related errors


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