jackwener/OpenCLI · error · CommandExecutionError
Suno feed lookup failed: ${feedRes?.error || 'unknown'}
Error message
Suno feed lookup failed: ${feedRes?.error || 'unknown'} What it means
Before downloading, the command queries Suno's studio API /api/feed/v3 in-page (with the Clerk session token and device id) to fetch the clip object. If that request fails (non-OK HTTP or a malformed payload), the result carries ok:false with an error string, and the command throws CommandExecutionError `Suno feed lookup failed: <reason>`.
Source
Thrown at clis/suno/download.js:105
const browserToken = JSON.stringify({ token: btoa(JSON.stringify({ timestamp: Date.now() })) });
const res = await fetch('${STUDIO_API}/api/feed/v3', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + (await window.Clerk.session.getToken()),
'browser-token': browserToken,
'device-id': ${JSON.stringify(deviceId)},
'Content-Type': 'application/json',
},
body: JSON.stringify({ clip_ids: ['${clipId}'] }),
});
if (!res.ok) return { ok: false, error: 'HTTP ' + res.status };
const payload = await res.json().catch(() => null);
if (!payload || !Array.isArray(payload.clips)) return { ok: false, error: 'malformed clips payload' };
return { ok: true, clips: payload.clips };
})()`));
if (!feedRes?.ok) {
throw new CommandExecutionError(`Suno feed lookup failed: ${feedRes?.error || 'unknown'}`);
}
if (!Array.isArray(feedRes.clips)) {
throw new CommandExecutionError('Suno feed lookup returned malformed clips payload');
}
const clip = feedRes.clips.find(c => c.id === clipId);
if (!clip) {
throw new EmptyResultError('suno download', `Clip ${clipId} not found in your account. Confirm at ${SUNO_URL}/song/${clipId}.`);
}
if (clip.status !== 'complete') {
throw new CommandExecutionError(`Clip ${clipId} status is "${clip.status}" — not complete yet. Retry once generation finishes.`);
}
const result = await downloadSunoClip(page, clip, outputDir, formats, deviceId);
if (!result.written.some(w => w.ok)) {
throw new CommandExecutionError(`Suno download wrote no files for clip ${clipId}`);
}
const link = `${SUNO_URL}/song/${clip.id}`;
const writtenSummary = result.writtenView on GitHub (pinned to 49907e53dc)
Solutions
- Read the reason suffix — 'HTTP 401/403' means re-authenticate (run suno login), 'HTTP 429/5xx' means retry later
- Refresh the Suno session and re-run the download command
- Verify the clip UUID is valid and belongs to your account
- If 'malformed clips payload' persists, the Suno API schema may have changed — update the probe in clis/suno/download.js
Example fix
// before
Suno feed lookup failed: HTTP 401
// after — refresh auth then retry
await cli('suno', 'login');
await cli('suno', 'download', clipId, '--formats', 'mp3'); Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm auth is healthy before the download
try { await cli('suno', 'whoami'); }
catch { await cli('suno', 'login'); } Type guard
function isFeedLookupError(e) {
return e instanceof Error && /Suno feed lookup failed:/.test(e.message);
}
function isRetryableFeedReason(reason) { return /HTTP (429|5\d\d)/.test(String(reason)); } Try / catch
try {
await cli('suno', 'download', clipId);
} catch (e) {
if (isFeedLookupError(e)) {
const reason = e.message.split('failed: ')[1];
if (/HTTP 40[13]/.test(reason)) { await cli('suno', 'login'); return cli('suno', 'download', clipId); }
if (isRetryableFeedReason(reason)) { await sleep(5000); return cli('suno', 'download', clipId); }
}
throw e;
} Prevention
- Refresh the Suno session (login) before long batch download runs
- Back off and retry on 429/5xx feed failures
- Validate clip UUIDs belong to your account before downloading
- Watch for Suno studio API schema changes if 'malformed clips payload' recurs
When it happens
Trigger: POST https://studio-api.suno.ai/api/feed/v3 returns non-2xx (e.g. HTTP 401 when the Clerk token expired, 404, 429, 5xx), or the response JSON has no clips array (error: 'malformed clips payload').
Common situations: Session token expired mid-run; Suno API outage or rate limiting; window.Clerk.session.getToken() returning a stale token; clip id referencing another account (paired with a later not-found); API schema change removing clips array.
Related errors
- ${label} returned HTTP ${resp.status}: ${summarizeApiError(p
- arXiv API HTTP ${resp.status}
- 获取视频分P信息失败: ${error?.message || error}
- 获取视频信息失败: ${err?.message || err}
- 获取视频播放信息失败: ${err?.message || err}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/1eef9e08465f8329.
Report an issue: GitHub.