jackwener/OpenCLI · error · CommandExecutionError
Reuters search returned a non-JSON body
Error message
Reuters search returned a non-JSON body${detail} What it means
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.
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.
Example fix
// before
const result = await page.evaluate(buildSearchScript(query, limit));
// after: detect HTML challenge body before parsing
const ct = resp.headers.get('content-type') || '';
const text = await resp.text();
if (!ct.includes('json') || /<html/i.test(text)) return { ok: true, parseError: 'non-JSON body (challenge page?)' };
return { ok: true, body: JSON.parse(text) }; Defensive patterns
Strategy: validation
Validate before calling
// pre-flight: confirm the tab serves JSON, not a challenge page
const probe = await page.evaluate(() => fetch('/api?probe=1').then(r => r.headers.get('content-type')).catch(() => ''));
if (!probe.includes('json')) throw new Error('Reuters is serving non-JSON (challenge?) — clear it in the browser first'); Type guard
function hasParsedBody(result) {
return typeof result === 'object' && result !== null && result.ok === true &&
result.body !== null && typeof result.body === 'object' && !result.parseError;
} Try / catch
try {
const rows = await cli.run('reuters search', { query });
} catch (e) {
if (e.message.includes('non-JSON body')) {
await clearChallengeInBrowser('https://www.reuters.com');
return cli.run('reuters search', { query });
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- archive search returned malformed JSON
- archive wayback returned malformed JSON
- eastmoney convertible returned invalid JSON
- hf models returned malformed JSON
- invalid JSON from
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/459be303aa63820c.
Report an issue: GitHub.
Appendix: source
Thrown at clis/reuters/search.js:52
}
if (!result || typeof result !== 'object') {
throw new CommandExecutionError('Reuters search API returned an unreadable response');
}
if (isAuthStatus(result.status) || looksAuthWallText(result.textPreview)) {
throw new AuthRequiredError(
'www.reuters.com',
`Reuters search requires an accessible Reuters browser session or completed human verification${result.status ? ` (HTTP ${result.status})` : ''}`,
);
}
if (result.ok !== true) {
const status = Number.isFinite(result.status) && result.status > 0
? `HTTP ${result.status}${result.statusText ? ` ${result.statusText}` : ''}`
: 'no upstream response';
throw new CommandExecutionError(`Reuters search API failed (${status})`);
}
if (!result.body) {
const detail = result.parseError ? `: ${result.parseError}` : '';
throw new CommandExecutionError(
`Reuters search returned a non-JSON body${detail}`,
'Open www.reuters.com in your browser and clear any challenge before retrying.',
);
}
const rows = mapSearchArticles(result.body, limit);
if (!rows.length) {
throw new EmptyResultError('reuters search', `No articles matched "${query}". Try broadening the query.`);
}
return rows;
},
});
View on GitHub (pinned to 49907e53dc)