{"record":{"id":"4245f28fe9080def","repo":"jackwener/OpenCLI","slug":"clip-clipid-status-is-clip-status-not-co","errorCode":null,"errorMessage":"Clip ${clipId} status is \"${clip.status}\" — not complete yet. Retry once generation finishes.","messagePattern":"Clip (.+?) status is \"(.+?)\" — not complete yet\\. Retry once generation finishes\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"warning","filePath":"clis/suno/download.js","lineNumber":115,"sourceCode":"            });\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\n            .map(w => w.ok ? `${w.format}:${displayPath(w.file)}` : `${w.format}:✗(${w.reason})`)\n            .join(' | ');\n        const skippedSummary = skippedPaid.length\n            ? ` | skipped(needs --confirm-paid):${skippedPaid.join(',')}`\n            : '';\n        const fileSummary = `${writtenSummary}${skippedSummary}`;\n        const anyFailed = result.written.some(w => !w.ok);\n\n        return [{\n            status: anyFailed ? '⚠ partial' : '✅ saved',","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/suno/download.js#L97-L133","documentation":"Thrown by `opencli suno download` when the clip was found but its `status` is anything other than 'complete'. Suno clips go through queued/submitting/running states during generation; only complete clips have downloadable audio. The error surfaces the actual status so you know to wait.","triggerScenarios":"Running `opencli suno download <clip-id>` immediately after `suno generate` or from the web UI while Suno is still generating the song (status e.g. 'running', 'queued', 'submitting'), or when generation actually failed/stuck in a non-complete state.","commonSituations":"Scripting download right after generate without polling, using --sd on generate then downloading immediately, or a clip stuck due to a Suno-side generation failure.","solutions":["Wait for generation to finish (typically 1–2 minutes) and retry the download command.","If you control the script, poll the clip status or add a delay/sleep before downloading (generate already polls with --timeout when not using --sd).","Check the clip at the printed suno.com/song/<id> link — if it is stuck in a non-complete state for a long time, generation failed; regenerate.","Retry once; if the status never becomes complete, the clip errored server-side and cannot be downloaded."],"exampleFix":"// before\nconst { clipIds } = await run('opencli suno generate \"song\" --sd true');\nawait run(`opencli suno download ${clipIds[0]}`); // too early\n// after\nconst { clipIds } = await run('opencli suno generate \"song\" --sd true');\nawait sleep(120000); // or poll status until 'complete'\nawait run(`opencli suno download ${clipIds[0]}`);","handlingStrategy":"retry","validationCode":"// poll the clip page/API before downloading; only download when status is 'complete'\nasync function waitUntilComplete(clipId, { timeoutMs = 300000, intervalMs = 15000 } = {}) {\n  const start = Date.now();\n  while (Date.now() - start < timeoutMs) {\n    const status = await getClipStatus(clipId); // e.g. via suno.com/song/<id>\n    if (status === 'complete') return;\n    if (['error', 'failed'].includes(status)) throw new Error('generation failed');\n    await new Promise(r => setTimeout(r, intervalMs));\n  }\n  throw new Error('timed out waiting for clip');\n}","typeGuard":"const isComplete = (clip) => clip?.status === 'complete';","tryCatchPattern":"for (let attempt = 0; attempt < 5; attempt++) {\n  try { await run(`opencli suno download ${clipId}`); break; }\n  catch (err) {\n    if (!String(err.message).includes('not complete yet')) throw err;\n    await new Promise(r => setTimeout(r, 30000)); // back off and retry\n  }\n}","preventionTips":["Don't use --sd on generate if you plan to download immediately — plain generate already polls until complete.","Add a 1–2 minute delay or status poll between generation and download in scripts.","Treat long-stuck non-complete status as a failed generation and regenerate."],"tags":["suno","async","polling","race-condition"],"backgroundTag":"resource-not-ready","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}