jackwener/OpenCLI · error · CommandExecutionError
eastmoney convertible returned a malformed data envelope
Error message
eastmoney convertible returned a malformed data envelope
What it means
Thrown by extractConvertibleDiff (clis/eastmoney/convertible.js:64) when the top-level object parsed from the eastmoney push2 response lacks a valid `data` sub-object (missing, null, a primitive, or an array). The push2 clist API normally nests the result rows at `data.diff`, so the CLI requires `data` to be a plain object before reading `.diff`. This is a CommandExecutionError indicating the API contract changed or the response was truncated/empty.
Source
Thrown at clis/eastmoney/convertible.js:64
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 trigger
// price (= convPrice × 0.7) and f238 is the pure-bond premium %. Real YTM /
// remaining term are not in this response's `fields`; adding the correct f-codes
// is a follow-up that needs a live push2 field dump cross-checked against jisilu.View on GitHub (pinned to 49907e53dc)
Solutions
- Retry the request; soft-empty responses are frequently transient.
- Check HTTP status was 200 and log the raw body to confirm `data` is genuinely absent rather than an auth rejection.
- Verify the `ut` token and `fs=b:MK0354` query params are still valid against the live push2 API.
- Try a different network/User-Agent if a soft block is suspected.
- Guard in caller code: check `data && data.data && typeof data.data === 'object'` before extracting diff.
Example fix
// before
const diff = extractConvertibleDiff(await resp.json());
// after
const json = await resp.json();
if (!json?.data || typeof json.data !== 'object' || Array.isArray(json.data)) {
throw new Error('eastmoney response missing data envelope: ' + JSON.stringify(json).slice(0, 200));
}
const diff = extractConvertibleDiff(json); Defensive patterns
Strategy: validation
Validate before calling
if (!json || typeof json !== 'object' || Array.isArray(json) || !json.data || typeof json.data !== 'object' || Array.isArray(json.data)) {
throw new Error('eastmoney response missing data envelope');
} Type guard
function hasDataEnvelope(v) {
return v !== null && typeof v === 'object' && !Array.isArray(v) &&
v.data !== null && typeof v.data === 'object' && !Array.isArray(v.data);
} Try / catch
try {
const diff = extractConvertibleDiff(json);
} catch (e) {
if (String(e.message).includes('malformed data envelope')) {
console.warn('empty/soft-blocked response, retrying once');
return retryWithBackoff(fetchConvertible);
}
throw e;
} Prevention
- Treat HTTP 200 + empty `data` as a possible soft block and retry.
- Keep the `ut` token and fs=b:MK0354 params up to date.
- Avoid datacenter IPs that eastmoney soft-blocks with empty payloads.
- Assert the envelope shape in integration tests with recorded fixtures.
When it happens
Trigger: The eastmoney endpoint returns `{}` or `{ rc:..., data: null }` — typical when the `fs=b:MK0354` board has no data for the query, the `ut` token is rejected, or the request was rate-limited into an empty success (HTTP 200 with an empty payload).
Common situations: Calling with sort/limit combinations the backend refuses silently; eastmoney rotating or invalidating the hard-coded `ut` token; regional restrictions returning empty envelopes; scraping from a datacenter IP that gets soft-blocked with an empty 200.
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 response envelope
- eastmoney convertible returned malformed diff data
- HTTP_ERROR
- NO_DATA
- eastmoney convertible returned malformed ${field} for ${bond
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/3e88994c48b544a2.
Report an issue: GitHub.