{"record":{"id":"459be303aa63820c","repo":"jackwener/OpenCLI","slug":"reuters-search-returned-a-non-json-body-detail","errorCode":null,"errorMessage":"Reuters search returned a non-JSON body${detail}","messagePattern":"Reuters search returned a non-JSON body(.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/reuters/search.js","lineNumber":52,"sourceCode":"        }\n        if (!result || typeof result !== 'object') {\n            throw new CommandExecutionError('Reuters search API returned an unreadable response');\n        }\n        if (isAuthStatus(result.status) || looksAuthWallText(result.textPreview)) {\n            throw new AuthRequiredError(\n                'www.reuters.com',\n                `Reuters search requires an accessible Reuters browser session or completed human verification${result.status ? ` (HTTP ${result.status})` : ''}`,\n            );\n        }\n        if (result.ok !== true) {\n            const status = Number.isFinite(result.status) && result.status > 0\n                ? `HTTP ${result.status}${result.statusText ? ` ${result.statusText}` : ''}`\n                : 'no upstream response';\n            throw new CommandExecutionError(`Reuters search API failed (${status})`);\n        }\n        if (!result.body) {\n            const detail = result.parseError ? `: ${result.parseError}` : '';\n            throw new CommandExecutionError(\n                `Reuters search returned a non-JSON body${detail}`,\n                'Open www.reuters.com in your browser and clear any challenge before retrying.',\n            );\n        }\n        const rows = mapSearchArticles(result.body, limit);\n        if (!rows.length) {\n            throw new EmptyResultError('reuters search', `No articles matched \"${query}\". Try broadening the query.`);\n        }\n        return rows;\n    },\n});\n","sourceCodeStart":34,"sourceCodeEnd":64,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/reuters/search.js#L34-L64","documentation":"CommandExecutionError thrown when the Reuters search API responded but the body could not be produced as JSON (result.body is falsy). If the page script captured a parseError, it is appended to the message. The remediation hint tells the user to open www.reuters.com and clear any challenge before retrying, because Datadome often returns HTML challenge pages instead of JSON.","triggerScenarios":"The in-page fetch returned ok:true but response.json() failed or returned nothing — typically the response was an HTML Datadome challenge page, an empty body, or Reuters changed the response format.","commonSituations":"Datadome serving an interstitial HTML page that still returns 200; empty 204/HTML responses from an edge cache; Reuters shipping a new response schema breaking the parser; compressed/undecodable responses in the tab context.","solutions":["Open www.reuters.com in the browser session, complete any challenge, then retry (per the error's own hint).","Re-run the search — challenge pages are often one-off interstitials.","If parseError mentions a schema/field mismatch, update buildSearchScript/mapSearchArticles in clis/reuters/utils.js to match Reuters' new response format.","Check the logged parseError detail to distinguish a challenge page from a format change."],"exampleFix":"// before\nconst result = await page.evaluate(buildSearchScript(query, limit));\n// after: detect HTML challenge body before parsing\nconst ct = resp.headers.get('content-type') || '';\nconst text = await resp.text();\nif (!ct.includes('json') || /<html/i.test(text)) return { ok: true, parseError: 'non-JSON body (challenge page?)' };\nreturn { ok: true, body: JSON.parse(text) };","handlingStrategy":"validation","validationCode":"// pre-flight: confirm the tab serves JSON, not a challenge page\nconst probe = await page.evaluate(() => fetch('/api?probe=1').then(r => r.headers.get('content-type')).catch(() => ''));\nif (!probe.includes('json')) throw new Error('Reuters is serving non-JSON (challenge?) — clear it in the browser first');","typeGuard":"function hasParsedBody(result) {\n  return typeof result === 'object' && result !== null && result.ok === true &&\n    result.body !== null && typeof result.body === 'object' && !result.parseError;\n}","tryCatchPattern":"try {\n  const rows = await cli.run('reuters search', { query });\n} catch (e) {\n  if (e.message.includes('non-JSON body')) {\n    await clearChallengeInBrowser('https://www.reuters.com');\n    return cli.run('reuters search', { query });\n  }\n  throw e;\n}","preventionTips":["Clear Datadome challenges promptly; don't reuse a challenged session.","Check content-type in the in-page fetch before JSON.parse and capture parseError detail.","Re-validate the mapper after any Reuters API response-format change.","Retry once on this error — challenge interstitials are frequently transient."],"tags":["json","parsing","anti-bot","network"],"backgroundTag":"non-json-response-body","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}