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.written

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the reason suffix — 'HTTP 401/403' means re-authenticate (run suno login), 'HTTP 429/5xx' means retry later
  2. Refresh the Suno session and re-run the download command
  3. Verify the clip UUID is valid and belongs to your account
  4. 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

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


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