jackwener/OpenCLI · warning · CommandExecutionError

Clip ${clipId} status is "${clip.status}" — not complete yet

Error message

Clip ${clipId} status is "${clip.status}" — not complete yet. Retry once generation finishes.

What it means

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.

Source

Thrown at clis/suno/download.js:115

            });
            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.written
            .map(w => w.ok ? `${w.format}:${displayPath(w.file)}` : `${w.format}:✗(${w.reason})`)
            .join(' | ');
        const skippedSummary = skippedPaid.length
            ? ` | skipped(needs --confirm-paid):${skippedPaid.join(',')}`
            : '';
        const fileSummary = `${writtenSummary}${skippedSummary}`;
        const anyFailed = result.written.some(w => !w.ok);

        return [{
            status: anyFailed ? '⚠ partial' : '✅ saved',

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Wait for generation to finish (typically 1–2 minutes) and retry the download command.
  2. 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).
  3. 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.
  4. Retry once; if the status never becomes complete, the clip errored server-side and cannot be downloaded.

Example fix

// before
const { clipIds } = await run('opencli suno generate "song" --sd true');
await run(`opencli suno download ${clipIds[0]}`); // too early
// after
const { clipIds } = await run('opencli suno generate "song" --sd true');
await sleep(120000); // or poll status until 'complete'
await run(`opencli suno download ${clipIds[0]}`);
Defensive patterns

Strategy: retry

Validate before calling

// poll the clip page/API before downloading; only download when status is 'complete'
async function waitUntilComplete(clipId, { timeoutMs = 300000, intervalMs = 15000 } = {}) {
  const start = Date.now();
  while (Date.now() - start < timeoutMs) {
    const status = await getClipStatus(clipId); // e.g. via suno.com/song/<id>
    if (status === 'complete') return;
    if (['error', 'failed'].includes(status)) throw new Error('generation failed');
    await new Promise(r => setTimeout(r, intervalMs));
  }
  throw new Error('timed out waiting for clip');
}

Type guard

const isComplete = (clip) => clip?.status === 'complete';

Try / catch

for (let attempt = 0; attempt < 5; attempt++) {
  try { await run(`opencli suno download ${clipId}`); break; }
  catch (err) {
    if (!String(err.message).includes('not complete yet')) throw err;
    await new Promise(r => setTimeout(r, 30000)); // back off and retry
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/4245f28fe9080def. Report an issue: GitHub.