{"record":{"id":"1eef9e08465f8329","repo":"jackwener/OpenCLI","slug":"suno-feed-lookup-failed-feedres-error-unkn","errorCode":null,"errorMessage":"Suno feed lookup failed: ${feedRes?.error || 'unknown'}","messagePattern":"Suno feed lookup failed: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/suno/download.js","lineNumber":105,"sourceCode":"            const browserToken = JSON.stringify({ token: btoa(JSON.stringify({ timestamp: Date.now() })) });\n            const res = await fetch('${STUDIO_API}/api/feed/v3', {\n                method: 'POST',\n                headers: {\n                    'Authorization': 'Bearer ' + (await window.Clerk.session.getToken()),\n                    'browser-token': browserToken,\n                    'device-id': ${JSON.stringify(deviceId)},\n                    'Content-Type': 'application/json',\n                },\n                body: JSON.stringify({ clip_ids: ['${clipId}'] }),\n            });\n            if (!res.ok) return { ok: false, error: 'HTTP ' + res.status };\n            const payload = await res.json().catch(() => null);\n            if (!payload || !Array.isArray(payload.clips)) return { ok: false, error: 'malformed clips payload' };\n            return { ok: true, clips: payload.clips };\n        })()`));\n\n        if (!feedRes?.ok) {\n            throw new CommandExecutionError(`Suno feed lookup failed: ${feedRes?.error || 'unknown'}`);\n        }\n        if (!Array.isArray(feedRes.clips)) {\n            throw new CommandExecutionError('Suno feed lookup returned malformed clips payload');\n        }\n        const clip = feedRes.clips.find(c => c.id === clipId);\n        if (!clip) {\n            throw new EmptyResultError('suno download', `Clip ${clipId} not found in your account. Confirm at ${SUNO_URL}/song/${clipId}.`);\n        }\n        if (clip.status !== 'complete') {\n            throw new CommandExecutionError(`Clip ${clipId} status is \"${clip.status}\" — not complete yet. Retry once generation finishes.`);\n        }\n\n        const result = await downloadSunoClip(page, clip, outputDir, formats, deviceId);\n        if (!result.written.some(w => w.ok)) {\n            throw new CommandExecutionError(`Suno download wrote no files for clip ${clipId}`);\n        }\n        const link = `${SUNO_URL}/song/${clip.id}`;\n        const writtenSummary = result.written","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/suno/download.js#L87-L123","documentation":"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>`.","triggerScenarios":"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').","commonSituations":"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.","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"],"exampleFix":"// before\nSuno feed lookup failed: HTTP 401\n// after — refresh auth then retry\nawait cli('suno', 'login');\nawait cli('suno', 'download', clipId, '--formats', 'mp3');","handlingStrategy":"try-catch","validationCode":"// Confirm auth is healthy before the download\ntry { await cli('suno', 'whoami'); }\ncatch { await cli('suno', 'login'); }","typeGuard":"function isFeedLookupError(e) {\n  return e instanceof Error && /Suno feed lookup failed:/.test(e.message);\n}\nfunction isRetryableFeedReason(reason) { return /HTTP (429|5\\d\\d)/.test(String(reason)); }","tryCatchPattern":"try {\n  await cli('suno', 'download', clipId);\n} catch (e) {\n  if (isFeedLookupError(e)) {\n    const reason = e.message.split('failed: ')[1];\n    if (/HTTP 40[13]/.test(reason)) { await cli('suno', 'login'); return cli('suno', 'download', clipId); }\n    if (isRetryableFeedReason(reason)) { await sleep(5000); return cli('suno', 'download', clipId); }\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["network","api","suno","feed"],"backgroundTag":"upstream-api-request-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}