jackwener/OpenCLI · error · CliError
PARSE_ERROR
PARSE_ERROR
Error message
Invalid JSON response for ${path} What it means
After receiving the HTTP response, postWebApiWithCookies attempts resp.json(); if the body is not valid JSON (commonly an HTML login/error page or a gateway block page), it throws this CliError with code PARSE_ERROR naming the API path. WeRead returns HTML instead of JSON when it intercepts the request (login redirect, WAF/captcha, maintenance).
Source
Thrown at clis/weread/ai-outline.js:42
headers: {
'User-Agent': WEREAD_UA,
'Content-Type': 'application/json',
'Origin': WEREAD_WEB_ORIGIN,
'Referer': `${WEREAD_WEB_ORIGIN}/`,
...(cookieHeader ? { 'Cookie': cookieHeader } : {}),
},
body: JSON.stringify(body),
});
if (resp.status === 401) {
throw new CliError('AUTH_REQUIRED', 'Not logged in to WeRead', 'Please log in to weread.qq.com in Chrome first');
}
let data;
try {
data = await resp.json();
} catch {
throw new CliError('PARSE_ERROR', `Invalid JSON response for ${path}`, 'WeRead may have returned an HTML error page');
}
if (data?.errcode === -2010 || data?.errcode === -2012) {
throw new CliError('AUTH_REQUIRED', 'Not logged in to WeRead', 'Please log in to weread.qq.com in Chrome first');
}
if (!resp.ok) {
throw new CliError('FETCH_ERROR', `HTTP ${resp.status} for ${path}`, 'WeRead API may be temporarily unavailable');
}
return data;
}
async function postWebApi(path, body) {
const url = `${WEB_API}${path}`;
const resp = await fetch(url, {
method: 'POST',
headers: {
'User-Agent': WEREAD_UA,
'Content-Type': 'application/json',View on GitHub (pinned to 49907e53dc)
Solutions
- Re-login to weread.qq.com in Chrome so requests stop being redirected to the HTML login page.
- Retry later if WeRead is rate limiting or under maintenance; reduce request frequency.
- Disable or bypass proxy/VPN interference that may inject HTML into responses.
- Inspect the raw response (curl the same endpoint with your cookies) to see what HTML is being returned.
Example fix
// before
const data = await postWebApiWithCookies('/book/chapter', body); // PARSE_ERROR on HTML page
// after: refresh session first, then retry with backoff
await refreshCookiesFromChrome();
const data = await retry(() => postWebApiWithCookies('/book/chapter', body), { retries: 2 }); Defensive patterns
Strategy: retry
Try / catch
const fetchJson = withRetry(async (path, body) => {
try {
return await postWebApiWithCookies(path, body);
} catch (e) {
if (e instanceof CliError && e.code === 'PARSE_ERROR') {
if (attempts < 3) return null; // signal retry after backoff (session refresh first)
throw e;
}
throw e;
}
}, { retries: 3, backoffMs: 1000 }); Prevention
- Keep the WeRead session fresh so the server doesn't answer with HTML login redirects.
- Throttle request rate; HTML challenge pages often follow bursts of requests.
- Avoid routing through proxies/VPNs that can inject HTML.
- Log the response Content-Type and first bytes when debugging to confirm an HTML interstitial.
When it happens
Trigger: chapterData calling the web API and WeRead responding with an HTML page (login redirect, anti-bot challenge, rate-limit page) or a non-2xx empty body, so resp.json() rejects.
Common situations: Expired session causing a redirect to the login page; WeRead serving a captcha/security-check page; corporate proxy or VPN injecting HTML; server-side outage returning an error 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
- Chess.com callback returned malformed JSON for ${url}: ${err
- Ctrip flight API returned invalid JSON
- mdn search returned malformed JSON: ${err?.message ?? err}
- ${label} returned malformed JSON: ${err?.message ?? err}
- Malformed JSON from Stack Exchange API for ${label}: ${detai
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/13abe5b0b0d82c94.
Report an issue: GitHub.