jackwener/OpenCLI · error · CommandExecutionError
hf datasets returned malformed JSON: ${error?.message || err
Error message
hf datasets returned malformed JSON: ${error?.message || error} What it means
The datasets API response body could not be parsed as JSON (resp.json() threw), so the command throws CommandExecutionError with the parse error message. This usually means the endpoint returned HTML (error page, login/redirect page) instead of JSON.
Source
Thrown at clis/hf/datasets.js:65
let resp;
try {
resp = await fetch(url, {
headers: {
'Accept': 'application/json',
'User-Agent': 'opencli/1.0 (+https://github.com/jackwener/opencli)',
},
});
} catch (error) {
throw new CommandExecutionError(`hf datasets request failed: ${error?.message || error}`);
}
if (!resp.ok) {
throw new CommandExecutionError(`hf datasets failed: HTTP ${resp.status}`);
}
let data;
try {
data = await resp.json();
} catch (error) {
throw new CommandExecutionError(`hf datasets returned malformed JSON: ${error?.message || error}`);
}
const list = Array.isArray(data) ? data : [];
if (list.length === 0) {
throw new EmptyResultError('hf datasets', 'No matching datasets on huggingface.co.');
}
return list.slice(0, limit).map((d, i) => {
const id = d.id || '';
const slashIdx = id.indexOf('/');
const author = slashIdx > 0 ? id.slice(0, slashIdx) : '';
const tags = Array.isArray(d.tags) ? d.tags.filter(t => !t.startsWith('license:')).slice(0, 10).join(', ') : '';
return {
rank: i + 1,
id,
author,
downloads: d.downloads ?? 0,
likes: d.likes ?? 0,
tags,
lastModified: d.lastModified ? String(d.lastModified).slice(0, 10) : '',View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the raw response body (curl the same URL) to see what was actually returned
- Bypass or correctly configure proxies that rewrite responses
- Retry if the response was truncated; check Accept: application/json header is sent
- Update the CLI if HF changed the endpoint's content type
Example fix
// before
data = await resp.json(); // throws on HTML
// after
const text = await resp.text(); try { data = JSON.parse(text); } catch (e) { console.error('non-JSON body:', text.slice(0, 200)); } Defensive patterns
Strategy: fallback
Validate before calling
const pre = await fetch(url, { headers: { Accept: 'application/json' } }); const ct = pre.headers.get('content-type') || ''; if (!ct.includes('application/json')) throw new Error(`expected JSON, got ${ct}`); Type guard
function isDatasetArray(v) { return Array.isArray(v) && v.every(d => d && typeof d.id === 'string'); } Try / catch
try { await hfDatasets(args); } catch (e) { if (String(e.message).includes('malformed JSON')) { console.error('non-JSON body from HF (proxy/HTML page?); bypass proxy or retry'); return null; } throw e; } Prevention
- Always send Accept: application/json
- Verify proxies/gateways do not rewrite responses
- Check content-type before parsing JSON
- Retry on truncated responses
When it happens
Trigger: resp.json() rejects: HF returned an HTML error/interstitial page, empty body, or truncated response due to proxy/gateway interference.
Common situations: Captive portal or proxy returning HTML; HF serving a 200 HTML maintenance page; content-encoding mismatch; network truncation.
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
- hf models returned malformed JSON: ${error?.message || error
- hf spaces returned malformed JSON: ${err?.message ?? err}
- ${label} returned malformed JSON: ${err?.message ?? err}
- archive search returned malformed JSON: ${error?.message ||
- archive wayback returned malformed JSON: ${error?.message ||
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/29e8c2f85d353628.
Report an issue: GitHub.