{"record":{"id":"02908659079054da","repo":"jackwener/OpenCLI","slug":"json-parse-failed-status-r-status-body-0-50","errorCode":null,"errorMessage":"JSON parse failed (status=${r.status}, body[0..50]=${JSON.stringify(trimmed.slice(0, 50))}): ${(err && err.message ? err.message : String(err))}","messagePattern":"JSON parse failed \\(status=(.+?), body\\[0\\.\\.50\\]=(.+?)\\): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/utils.ts","lineNumber":206,"sourceCode":"  const looksLikeHtml =\n    contentType.toLowerCase().includes('text/html')\n    || /^<(?:!doctype|html|head|body|title)(?:[\\\\s>/]|$)/i.test(trimmed);\n  if (looksLikeHtml) {\n    return {\n      __loginWall: true,\n      status: r.status,\n      url: r.url || (typeof input === 'string' ? input : ''),\n      contentType,\n      bodyPreview: trimmed.slice(0, 100),\n    };\n  }\n  if (!r.ok) {\n    return { error: r.status };\n  }\n  try {\n    return JSON.parse(text);\n  } catch (err) {\n    throw new Error(\n      'JSON parse failed (status=' + r.status + ', body[0..50]=' + JSON.stringify(trimmed.slice(0, 50)) + '): '\n      + (err && err.message ? err.message : String(err))\n    );\n  }\n}\n`;\n","sourceCodeStart":188,"sourceCodeEnd":213,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/src/utils.ts#L188-L213","documentation":"This is the browser-side twin of the JSON parse guard: injected script code (embedded in a template string in src/utils.ts) that, after a fetch where r.ok, JSON.parses the text and on failure throws an Error with the status, a 50-char body preview, and the parser message. It surfaces malformed JSON to the Node side with enough context to debug without re-running in the browser.","triggerScenarios":"Running injected fetch/parse code inside page.evaluate against an endpoint that returns r.ok but a body JSON.parse cannot handle (empty body, HTML that escaped the earlier check, truncated JSON).","commonSituations":"Page context fetches to endpoints behind experiments returning empty 200s; SPA dev servers intercepting API routes; responses cut off by browser network conditions; endpoints emitting BOM or non-UTF8 bytes.","solutions":["Use the body[0..50] preview in the message to identify the actual payload","Retry the in-page fetch; transient truncation is the most common cause","Verify the endpoint URL is correct in the page context (relative URLs resolve against the page origin)","Trim a leading BOM (\\uFEFF) from the text before JSON.parse if previews show it"],"exampleFix":"// before\nconst data = JSON.parse(text);\n// after\nconst clean = text.replace(/^\\uFEFF/, '').trim();\nconst data = JSON.parse(clean || 'null');","handlingStrategy":"retry","validationCode":"// Inside the injected script, before parsing:\nconst clean = text.replace(/^\\uFEFF/, '').trim();\nif (!clean) return { error: r.status, body: '' };","typeGuard":null,"tryCatchPattern":"try {\n  const data = await page.evaluate(script, url);\n} catch (e) {\n  if (/JSON parse failed/.test(String(e.message))) { console.error('In-page JSON malformed — retry or log body preview'); }\n  throw e;\n}","preventionTips":["Strip BOM/whitespace before JSON.parse in injected scripts","Retry in-page fetches once on parse failure before surfacing the error","Use absolute API URLs in page.evaluate to avoid origin-relative surprises","Log the 50-char body preview included in the message when debugging"],"tags":["json","browser-evaluate","parse-error","http"],"backgroundTag":"json-parse-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}