jackwener/OpenCLI · error · CommandExecutionError
eastmoney convertible returned a malformed response envelope
Error message
eastmoney convertible returned a malformed response envelope
What it means
Thrown by extractConvertibleDiff (clis/eastmoney/convertible.js:61) when the value returned from the eastmoney push2 clist API is not a plain object. The library expects the standard eastmoney envelope `{ data: { diff: [...] } }`; anything else (null, an array, a string, HTML text parsed leniently) fails this first envelope check. It is a CommandExecutionError, meaning the remote API response shape violated the contract the CLI relies on.
Source
Thrown at clis/eastmoney/convertible.js:61
throw new CommandExecutionError(`eastmoney convertible returned malformed ${field} for ${bondCode || 'unknown bond'}`);
}
export function parseConvertibleLimit(value) {
if (value === undefined || value === null || value === '') return 20;
if (typeof value === 'number') {
if (Number.isInteger(value) && value >= 1 && value <= 100) return value;
throw new ArgumentError('eastmoney convertible --limit must be an integer between 1 and 100');
}
const raw = String(value).trim();
if (!/^\d+$/.test(raw)) throw new ArgumentError('eastmoney convertible --limit must be an integer between 1 and 100');
const parsed = Number(raw);
if (parsed < 1 || parsed > 100) throw new ArgumentError('eastmoney convertible --limit must be an integer between 1 and 100');
return parsed;
}
export function extractConvertibleDiff(data) {
if (!data || typeof data !== 'object' || Array.isArray(data)) {
throw new CommandExecutionError('eastmoney convertible returned a malformed response envelope');
}
if (!data.data || typeof data.data !== 'object' || Array.isArray(data.data)) {
throw new CommandExecutionError('eastmoney convertible returned a malformed data envelope');
}
const diff = data.data.diff;
if (!Array.isArray(diff)) {
throw new CommandExecutionError('eastmoney convertible returned malformed diff data');
}
if (diff.length === 0) {
throw new EmptyResultError('eastmoney convertible');
}
return diff;
}
// Map a raw eastmoney clist `diff` item to an output row.
//
// #2109: f238 / f239 were previously emitted as `remainingYears` / `ytm`, but
// cross-verification (12/12 fingerprint hits) shows f239 is the putback triggerView on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the command; transient anti-bot blocks often clear on retry (ideally with a browser-like User-Agent).
- Verify the endpoint still returns JSON by curling https://push2.eastmoney.com/api/qt/clist/get with the same query params (fs=b:MK0354, ut=...).
- Check for proxy/VPN interference that replaces the JSON body with an HTML page.
- If eastmoney changed the envelope format, update extractConvertibleDiff to the new shape.
- In code, validate the response is a non-array object before calling extractConvertibleDiff.
Example fix
// before
const data = await resp.json();
const diff = extractConvertibleDiff(data);
// after
const data = await resp.json();
if (!data || typeof data !== 'object' || Array.isArray(data)) {
throw new Error('unexpected eastmoney response, not a JSON object');
}
const diff = extractConvertibleDiff(data); Defensive patterns
Strategy: type-guard
Validate before calling
function isPlainObject(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); }
if (!isPlainObject(response)) throw new Error('eastmoney response is not an object'); Type guard
function isValidEnvelope(v) {
return v !== null && typeof v === 'object' && !Array.isArray(v);
} Try / catch
try {
const diff = extractConvertibleDiff(data);
} catch (e) {
if (String(e.message).includes('malformed response envelope')) {
console.error('eastmoney returned a non-object body — likely blocked or changed API');
return fallbackFetch();
}
throw e;
} Prevention
- Always run extractConvertibleDiff on the parsed JSON, never on raw text.
- Check content-type is application/json before parsing.
- Log the first ~200 chars of unexpected bodies to diagnose blocks.
- Pin/verify the push2 endpoint URL against the live API periodically.
When it happens
Trigger: extractConvertibleDiff(data) is called with data that is null/undefined, a primitive, or an Array — e.g. the push2 endpoint returned `{}`-like content, an HTML error/anti-bot page that somehow parsed, or a proxy stripped the body. Callers: the `diff` step inside the `eastmoney convertible` cli func after `resp.json()` succeeds.
Common situations: Eastmoney WAF/anti-bot interception returning a non-API body; region-blocked or rate-limited responses returning empty payloads; a corporate proxy or captive portal injecting an HTML page; eastmoney changing or deprecating the `/api/qt/clist/get` response format; unit tests feeding mock data of the wrong shape.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- eastmoney convertible returned a malformed data envelope
- eastmoney convertible returned malformed diff data
- eastmoney convertible returned malformed row at rank ${rank}
- API_ERROR
- No user message found in request
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/8a5da8a152410360.
Report an issue: GitHub.