jackwener/OpenCLI · error · CommandExecutionError
${label} returned a malformed envelope
Error message
${label} returned a malformed envelope What it means
Nowcoder's JSON APIs wrap results in an envelope containing success (boolean), code (integer), and msg fields. fetchNowcoderData validates this envelope shape after a successful HTTP response; if the payload is not a record, success is not a boolean, or code is not a safe integer, it throws this CommandExecutionError because the response does not follow the expected Nowcoder API contract.
Source
Thrown at clis/nowcoder/posts.js:251
const number = Number(value);
if (!Number.isInteger(number) || number < 1 || number > maximum) throw new ArgumentError(`nowcoder --${name} must be an integer from 1 to ${maximum}`);
return number;
}
export async function fetchNowcoderData(page, url, options, label) {
let payload;
try {
await page.goto('https://www.nowcoder.com');
payload = await page.fetchJson(url, options);
}
catch (error) {
const detail = String(error?.message ?? error);
if (/HTTP\s+(401|403)|need login|not logged in/i.test(detail)) {
throw new AuthRequiredError('nowcoder.com', `${label} requires a logged-in Nowcoder session`);
}
throw new CommandExecutionError(`${label} failed: ${detail}`);
}
if (!isRecord(payload) || typeof payload.success !== 'boolean' || !Number.isSafeInteger(payload.code)) throw new CommandExecutionError(`${label} returned a malformed envelope`);
const message = typeof payload.msg === 'string' ? payload.msg : 'unknown error';
if (!payload.success || payload.code !== 0) {
if (payload.code === 999 || /need login|登录/i.test(message)) {
throw new AuthRequiredError('nowcoder.com', `${label} requires a logged-in Nowcoder session: ${message}`);
}
throw new CommandExecutionError(`${label} failed: ${message} (${payload.code})`);
}
if (!isRecord(payload.data)) throw new CommandExecutionError(`${label} returned malformed data`);
return payload.data;
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Retry — anti-bot interstitials are often transient; reduce request rate and add delays.
- Ensure you're logged in (an HTML login response can masquerade as a malformed envelope).
- Verify the endpoint URL used by the library is still current; update the library if Nowcoder changed the API shape.
- Capture the raw response to inspect what was actually returned and confirm the diagnosis.
Example fix
// before
// rapid scraping triggers anti-bot HTML with HTTP 200
await Promise.all(ids.map(getPost));
// after
// throttle and retry with backoff
for (const id of ids) { await getPost(id); await sleep(3000); } Defensive patterns
Strategy: retry
Type guard
function isNowcoderEnvelope(payload) {
return payload !== null && typeof payload === 'object' && !Array.isArray(payload)
&& typeof payload.success === 'boolean' && Number.isSafeInteger(payload.code);
} Try / catch
try {
const data = await fetchNowcoderData(page, url, options, label);
} catch (err) {
if (err instanceof CommandExecutionError && /malformed envelope/.test(err.message)) {
// usually an anti-bot HTML page with HTTP 200: back off and retry
await sleep(10000);
return fetchNowcoderData(page, url, options, label);
}
throw err;
} Prevention
- Throttle and randomize request timing to avoid anti-bot interstitials.
- Stay logged in — HTML login responses can masquerade as malformed envelopes.
- Keep the library current in case Nowcoder changes the envelope contract.
- Log the raw response once when this occurs to confirm what was returned.
When it happens
Trigger: The endpoint returned HTML (anti-bot challenge or error page parsed as JSON), a JSON array instead of an object, or a differently-shaped JSON object without the success/code fields.
Common situations: Hitting a WAF/anti-crawler interstitial that returns HTML with 200; Nowcoder changing its envelope schema; requesting the wrong endpoint URL that returns a non-envelope response; cookies prompting an HTML login page instead of JSON.
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
- Bilibili ${label} API returned a malformed payload
- Bilibili ${label} API returned malformed data
- Bilibili ${label} API did not return replies
- Bilibili ${label} API returned malformed replies
- Bilibili ${label} API did not return top_replies
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/ea481aeee07686bc.
Report an issue: GitHub.