jackwener/OpenCLI · error · CommandExecutionError

All Suno clips failed (${errors}). Open ${SUNO_URL}/song/${c

Error message

All Suno clips failed (${errors}). Open ${SUNO_URL}/song/${clipIds[0]} to inspect.

What it means

After polling, if none of the generated clips reached status 'complete', the CLI throws listing each clip's short id and terminal status, with a link to the first clip for manual inspection.

Source

Thrown at clis/suno/generate.js:184

            deviceId,
        });

        if (!Array.isArray(submission.clips)) {
            throw new CommandExecutionError('Suno generation returned malformed clips payload.');
        }
        const clipIds = submission.clips.map(c => c?.id);
        if (clipIds.some(id => !id)) {
            throw new CommandExecutionError('Suno generation returned malformed clip identity.');
        }
        if (!clipIds.length) {
            throw new CommandExecutionError('Suno accepted the request but returned no clip ids.');
        }

        const clips = await pollSunoClips(page, clipIds, timeout, deviceId);
        const completed = clips.filter(c => c.status === 'complete');
        if (!completed.length) {
            const errors = clips.map(c => `${c.id.slice(0, 8)}:${c.status}`).join(', ');
            throw new CommandExecutionError(`All Suno clips failed (${errors}). Open ${SUNO_URL}/song/${clipIds[0]} to inspect.`);
        }

        const rows = [];
        for (const clip of clips) {
            const link = `${SUNO_URL}/song/${clip.id}`;
            if (clip.status !== 'complete') {
                rows.push({
                    status: `❌ ${clip.status}`,
                    clip: clip.id.slice(0, 8),
                    title: clip.title || '(untitled)',
                    files: '-',
                    link: `🔗 ${link}`,
                });
                continue;
            }
            if (skipDownload) {
                rows.push({
                    status: '🎵 generated',

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Open the song URL from the message (https://suno.com/song/<clipId>) to see Suno's own failure reason.
  2. Read the per-clip statuses in the error (e.g. abc12345:error) — 'error' usually means moderation rejection, timeout means backlog.
  3. Retry with a longer --timeout if clips were still queued.
  4. Rephrase prompt/lyrics or switch --model and regenerate.

Example fix

// before: single 60s wait, gives up on slow queue
const clips = await pollSunoClips(page, clipIds, 60, deviceId);
// after: allow more time for Suno backlog
const clips = await pollSunoClips(page, clipIds, 300, deviceId);
Defensive patterns

Strategy: retry

Validate before calling

// Prefer generous timeouts up front; check account eligibility for the chosen model:
await opencli('suno', 'generate', prompt, '--timeout', '300'); // default 300s, raise for backlogs

Type guard

function anyCompleted(clips) { return Array.isArray(clips) && clips.some(c => c?.status === 'complete'); }

Try / catch

try {
  const rows = await opencli('suno', 'generate', prompt);
} catch (e) {
  const m = /All Suno clips failed \((.+)\)/.exec(e.message);
  if (m) {
    const statuses = m[1];
    if (/timeout/i.test(statuses)) await retryWithLongerTimeout();
    else if (/error|failed/i.test(statuses)) reportModerationOrContentIssue(statuses);
  } else throw e;
}

Prevention

When it happens

Trigger: `pollSunoClips()` returns clips where no `c.status === 'complete'` — all clips ended 'error', 'failed', or timed out in a non-complete state within --timeout.

Common situations: Content-moderation failure on the prompt/lyrics, Suno compute backlog causing timeouts, unsupported model tag, or lyrics with malformed metatags.

Related errors


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