jackwener/OpenCLI · error · CommandExecutionError
weread-official ${apiName} returned invalid JSON
Error message
weread-official ${apiName} returned invalid JSON What it means
response.json() failed, meaning the gateway returned a body that is not valid JSON (e.g. an HTML error page, empty body, or a proxy block page). callGateway converts this to CommandExecutionError with the parser's message as detail.
Source
Thrown at clis/weread-official/utils.js:117
}
finally {
clearTimeout(timer);
}
if (!response.ok) {
throw new CommandExecutionError(
`weread-official ${apiName} HTTP ${response.status}`,
'Check WeRead gateway availability and that WEREAD_API_KEY is still valid.',
);
}
let payload;
try {
payload = await response.json();
}
catch (error) {
const detail = error instanceof Error ? error.message : String(error);
throw new CommandExecutionError(`weread-official ${apiName} returned invalid JSON`, detail);
}
if (payload && typeof payload === 'object' && payload.upgrade_info) {
const info = payload.upgrade_info;
const required = info?.required_version ?? info?.version ?? 'unknown';
const message = info?.message ?? 'WeRead skill version is outdated';
throw new CommandExecutionError(
`WeRead skill 需升级: ${message}. Required skill_version=${required}, current=${SKILL_VERSION}`,
'Pull the latest weread-skills.zip and bump SKILL_VERSION in clis/weread-official/utils.js.',
);
}
const errcode = Number(payload?.errcode ?? 0);
if (errcode !== 0) {
const errmsg = String(payload?.errmsg ?? 'unknown error');
if (AUTH_ERRCODES.has(errcode)) {
throw new AuthRequiredError(
WEREAD_DOMAIN,View on GitHub (pinned to 49907e53dc)
Solutions
- Print the raw response body to see what was actually returned (likely HTML).
- Check for proxy/VPN interception and disable it or set NO_PROXY.
- Retry later if the gateway is serving a maintenance page.
- Verify the request is going to the correct gateway URL.
Defensive patterns
Strategy: try-catch
Validate before calling
const probe = await fetch(gatewayUrl, { method: 'HEAD' });
const ct = probe.headers.get('content-type') || '';
if (!ct.includes('json')) throw new Error(`Gateway returned ${ct || 'no content-type'} — likely HTML/proxy interception`); Type guard
const isBadJson = (e) => e instanceof CommandExecutionError && /invalid JSON/.test(e.message);
Try / catch
try {
return await callGateway(apiName, params);
} catch (e) {
if (e instanceof CommandExecutionError && /invalid JSON/.test(e.message)) {
console.error('Response was not JSON — check for proxy/VPN interception or gateway outage, then retry');
}
throw e;
} Prevention
- Disable VPN/proxy interception (add gateway domain to NO_PROXY)
- Detect captive portals before long scripts run
- Retry once on invalid JSON — outages are often transient
- Log raw bodies when debugging by disabling error wrapping temporarily
When it happens
Trigger: Gateway or an intermediary returning HTML (login page, 502 page, captcha challenge); truncated response; empty 200 response body; wrong content encoding.
Common situations: Captive portal or corporate proxy intercepting HTTPS; gateway outage serving an HTML maintenance page; hitting the wrong endpoint that returns a web page.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- ${label} returned a non-JSON response
- archive snapshots returned malformed JSON: ${error?.message
- COMMAND_EXEC
- `${label} returned malformed JSON: ${err?.message ?? err}`
- ${label} returned malformed JSON: ${err?.message ?? err}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/36ede38a9c8ef6fd.
Report an issue: GitHub.