jackwener/OpenCLI · error · CommandExecutionError
DuckDuckGo suggest returned malformed JSON: ${err?.message ?
Error message
DuckDuckGo suggest returned malformed JSON: ${err?.message ?? err} What it means
When the suggest endpoint responds 2xx but resp.json() throws, the command wraps the parse failure in a CommandExecutionError with the message 'DuckDuckGo suggest returned malformed JSON'. This happens when the body is not the expected JSON array-of-arrays shape — typically HTML (block page), an empty body, or truncated output.
Source
Thrown at clis/duckduckgo/suggest.js:35
columns: ['phrase'],
func: async (kwargs) => {
const limit = requireBoundedInteger(kwargs.limit, 8, 1, 20, '--limit');
const keyword = encodeURIComponent(requireSearchQuery(kwargs.keyword));
const url = `https://duckduckgo.com/ac/?q=${keyword}&type=list`;
let resp;
try {
resp = await fetch(url);
} catch (err) {
throw new CommandExecutionError(`DuckDuckGo suggest request failed: ${err instanceof Error ? err.message : String(err)}`);
}
if (!resp.ok) {
throw new CommandExecutionError(`DuckDuckGo suggest returned HTTP ${resp.status}`);
}
let data;
try {
data = await resp.json();
} catch (err) {
throw new CommandExecutionError(`DuckDuckGo suggest returned malformed JSON: ${err?.message ?? err}`);
}
const phrases = Array.isArray(data) && data.length > 1 && Array.isArray(data[1]) ? data[1] : [];
return phrases
.filter((phrase) => typeof phrase === 'string' && phrase.trim())
.slice(0, limit)
.map(function(p) { return { phrase: p }; });
},
});
export const __test__ = { command };
View on GitHub (pinned to 49907e53dc)
Solutions
- Log the raw response text on failure to see what was actually returned
- Reduce request rate and retry; add jittered backoff
- Verify no proxy/firewall is rewriting responses
- Catch CommandExecutionError and treat as 'no suggestions' for that keyword
- Update parsing if DuckDuckGo changes the /ac/ response format
Example fix
// before
const data = JSON.parse(rawBody); // throws generic SyntaxError
// after
try {
const data = await resp.json();
} catch (err) {
const body = await resp.text().catch(() => '');
console.error('unexpected body:', body.slice(0, 200));
return [];
} Defensive patterns
Strategy: fallback
Validate before calling
// sanity check content type before parsing expectations
const ct = resp.headers.get('content-type') ?? '';
if (!ct.includes('json')) {
console.warn('suggest returned non-JSON content-type:', ct);
} Type guard
function isSuggestPayload(d) {
return Array.isArray(d) && d.length > 1 && Array.isArray(d[1]) && d[1].every(p => typeof p === 'string');
} Try / catch
try {
return await ddgSuggest({ keyword });
} catch (err) {
if (/malformed JSON/.test(err?.message ?? '')) return []; // degrade gracefully
throw err;
} Prevention
- Reduce request rate — degraded/HTML responses often follow abuse detection
- Verify content-type before parsing when using raw fetch
- Return [] as a fallback so one bad response does not break batch jobs
- Capture the raw body on parse failure for diagnostics
When it happens
Trigger: resp.json() rejects: DuckDuckGo served an HTML error/anti-bot page with 200, empty body, or corrupted/truncated response; a proxy intercepted the response.
Common situations: Anti-bot interstitials returning 200 + HTML; captive portals in hotels/airports; aggressive request rates causing degraded responses; middlebox/proxy rewriting the body.
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
- coingecko categories returned malformed JSON: ${err?.message
- coingecko exchanges returned malformed JSON: ${err?.message
- coingecko returned malformed JSON: ${error?.message || error
- ${label} returned malformed JSON: ${err?.message ?? err}
- Manus skills returned a malformed API payload
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/85e308a26b51a765.
Report an issue: GitHub.