{"record":{"id":"13abe5b0b0d82c94","repo":"jackwener/OpenCLI","slug":"parse-error-13abe5","errorCode":"PARSE_ERROR","errorMessage":"Invalid JSON response for ${path}","messagePattern":"Invalid JSON response for (.+?)","errorType":"exception","errorClass":"CliError","httpStatus":null,"severity":"error","filePath":"clis/weread/ai-outline.js","lineNumber":42,"sourceCode":"        headers: {\n            'User-Agent': WEREAD_UA,\n            'Content-Type': 'application/json',\n            'Origin': WEREAD_WEB_ORIGIN,\n            'Referer': `${WEREAD_WEB_ORIGIN}/`,\n            ...(cookieHeader ? { 'Cookie': cookieHeader } : {}),\n        },\n        body: JSON.stringify(body),\n    });\n\n    if (resp.status === 401) {\n        throw new CliError('AUTH_REQUIRED', 'Not logged in to WeRead', 'Please log in to weread.qq.com in Chrome first');\n    }\n\n    let data;\n    try {\n        data = await resp.json();\n    } catch {\n        throw new CliError('PARSE_ERROR', `Invalid JSON response for ${path}`, 'WeRead may have returned an HTML error page');\n    }\n\n    if (data?.errcode === -2010 || data?.errcode === -2012) {\n        throw new CliError('AUTH_REQUIRED', 'Not logged in to WeRead', 'Please log in to weread.qq.com in Chrome first');\n    }\n    if (!resp.ok) {\n        throw new CliError('FETCH_ERROR', `HTTP ${resp.status} for ${path}`, 'WeRead API may be temporarily unavailable');\n    }\n    return data;\n}\n\nasync function postWebApi(path, body) {\n    const url = `${WEB_API}${path}`;\n    const resp = await fetch(url, {\n        method: 'POST',\n        headers: {\n            'User-Agent': WEREAD_UA,\n            'Content-Type': 'application/json',","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/weread/ai-outline.js#L24-L60","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst data = await postWebApiWithCookies('/book/chapter', body); // PARSE_ERROR on HTML page\n// after: refresh session first, then retry with backoff\nawait refreshCookiesFromChrome();\nconst data = await retry(() => postWebApiWithCookies('/book/chapter', body), { retries: 2 });","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"const fetchJson = withRetry(async (path, body) => {\n  try {\n    return await postWebApiWithCookies(path, body);\n  } catch (e) {\n    if (e instanceof CliError && e.code === 'PARSE_ERROR') {\n      if (attempts < 3) return null; // signal retry after backoff (session refresh first)\n      throw e;\n    }\n    throw e;\n  }\n}, { retries: 3, backoffMs: 1000 });","preventionTips":["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."],"tags":["parse-error","network","html-response"],"backgroundTag":"invalid-json-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}