jackwener/OpenCLI · error · CommandExecutionError
Suno feed API returned malformed JSON while polling clips
Error message
Suno feed API returned malformed JSON while polling clips
What it means
pollSunoClips expects /api/feed/v3 to return a JSON object. If res.json() fails (body null), or the parsed body is an array/primitive, this CommandExecutionError is thrown because the poll loop cannot read body.clips.
Source
Thrown at clis/suno/utils.js:381
headers: ${sunoHeadersJs(deviceId, { 'Content-Type': 'application/json' })},
body: JSON.stringify({ clip_ids: ${idsJson} }),
});
const body = await res.json().catch(() => null);
return { status: res.status, body };
})()`));
if (!result) {
await page.wait(pollSeconds);
continue;
}
if (result.status === 401 || result.status === 403) {
throw new AuthRequiredError(SUNO_DOMAIN, `Suno feed API rejected (HTTP ${result.status}). Re-login.`);
}
if (result.status < 200 || result.status >= 300) {
throw new CommandExecutionError(`Suno feed API failed while polling clips (HTTP ${result.status || '?'})`);
}
if (!result.body || typeof result.body !== 'object' || Array.isArray(result.body)) {
throw new CommandExecutionError('Suno feed API returned malformed JSON while polling clips');
}
const allClips = result.body.clips || [];
if (!Array.isArray(allClips)) {
throw new CommandExecutionError('Suno feed API returned malformed clips payload');
}
const ourClips = allClips.filter(c => targetSet.has(c.id));
const finished = ourClips.filter(c => c.status === 'complete' || c.status === 'error');
if (typeof onProgress === 'function') {
onProgress({ total: clipIds.length, done: finished.length, statuses: ourClips.map(c => `${c.id.slice(0,8)}:${c.status}`) });
}
if (finished.length === clipIds.length) return ourClips;
await page.wait(pollSeconds);
}
throw new TimeoutError(`Suno generation did not complete within ${timeoutSeconds}s. Try --timeout <higher>.`);View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run after a pause — challenge pages and truncation are often transient.
- Re-login to Suno to clear anti-bot/edge states, then retry.
- Inspect the raw response (add logging of res.text()) to identify what was returned.
- Update the CLI if Suno changed the /api/feed/v3 response format.
Example fix
// before
const body = await res.json().catch(() => null);
// after: capture raw text for diagnostics when JSON parse fails
const text = await res.text();
let body = null;
try { body = JSON.parse(text); } catch {}
return { status: res.status, body, raw: body ? null : text.slice(0, 300) }; Defensive patterns
Strategy: type-guard
Validate before calling
// after fetch, check parseability before consuming
const text = await res.text();
let body = null; try { body = JSON.parse(text); } catch {}
if (!body || typeof body !== 'object' || Array.isArray(body)) throw new Error('feed returned non-JSON body: ' + text.slice(0, 200)); Type guard
function isFeedBody(b) {
return !!b && typeof b === 'object' && !Array.isArray(b);
} Try / catch
try {
const clips = await pollSunoClips(page, ids, timeout, deviceId);
} catch (e) {
if (e instanceof CommandExecutionError && /malformed JSON/.test(e.message)) {
// likely a challenge/maintenance page; pause and retry
await sleep(20000);
return pollSunoClips(page, ids, timeout, deviceId);
}
throw e;
} Prevention
- Pause polling during suspected Suno maintenance windows
- Re-login if challenge pages appear repeatedly
- Capture raw response text for diagnostics
When it happens
Trigger: The feed endpoint returns 2xx with a non-JSON body (HTML error page, empty body), so res.json().catch(() => null) yields null, or the body parses to a non-object value.
Common situations: Suno serving a maintenance/Cloudflare challenge page with 2xx; truncated response; API version drift on /api/feed/v3; anti-bot interstitials when the session looks suspicious.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Suno generate returned malformed JSON payload.
- Bilibili ${label} API returned a malformed payload
- ${label} returned JSON without result.status.@code
- Flomo API returned a malformed response
- hf datasets returned malformed JSON: ${error?.message || err
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/53cb4e931c8f6aaa.
Report an issue: GitHub.