{"record":{"id":"d4b9bee51a7b972b","repo":"jackwener/OpenCLI","slug":"suno-generate-failed-http-status-detail","errorCode":null,"errorMessage":"Suno generate failed (HTTP ${status}): ${detail}","messagePattern":"Suno generate failed \\(HTTP (.+?)\\): (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/suno/utils.js","lineNumber":337,"sourceCode":"            headers: ${sunoHeadersJs(deviceId, { 'Content-Type': 'application/json' })},\n            body: ${JSON.stringify(bodyJson)},\n        });\n        const text = await res.text();\n        let parsed = null;\n        try { parsed = JSON.parse(text); } catch {}\n        return { status: res.status, ok: res.ok, body: parsed, raw: parsed ? null : text.slice(0, 600) };\n    })()`));\n\n    if (!result || !result.ok) {\n        const status = result?.status || 'unknown';\n        const detail = result?.body?.detail || result?.raw || JSON.stringify(result?.body || {}).slice(0, 500);\n        if (status === 401 || status === 403) {\n            throw new AuthRequiredError(SUNO_DOMAIN, `Suno API rejected request (HTTP ${status}). Re-login on suno.com.`);\n        }\n        if (status === 402) {\n            throw new CommandExecutionError(`Suno API: insufficient credits (HTTP 402). ${detail}`);\n        }\n        throw new CommandExecutionError(`Suno generate failed (HTTP ${status}): ${detail}`);\n    }\n\n    if (!result.body || typeof result.body !== 'object' || Array.isArray(result.body)) {\n        throw new CommandExecutionError('Suno generate returned malformed JSON payload.');\n    }\n    const clips = result.body?.clips || [];\n    if (!clips.length) {\n        throw new EmptyResultError('suno generate', `Submission accepted but Suno returned no clip ids. Raw: ${JSON.stringify(result.body).slice(0, 300)}`);\n    }\n    return result.body;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Poll /api/feed/v3 (cookie auth, no Bearer).\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function pollSunoClips(page, clipIds, timeoutSeconds, deviceId, pollSeconds = 5, onProgress = null) {\n    const deadline = Date.now() + timeoutSeconds * 1000;","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/suno/utils.js#L319-L355","documentation":"For any generate API failure that isn't auth (401/403) or credits (402), submitSunoGeneration throws CommandExecutionError('Suno generate failed (HTTP <status>): <detail>') where detail is body.detail, the raw body, or a truncated JSON dump. It is the catch-all for rejected generation requests.","triggerScenarios":"Suno returns 400 (invalid prompt/params, content-policy rejection), 429 (rate limit), 5xx (server error), or any other non-OK status from /api/generate/v2-web/ that doesn't match the auth/credit branches.","commonSituations":"Prompt violating Suno content policy (400); firing many generations back-to-back and hitting rate limits (429); Suno incident/server errors (5xx); invalid parameter combos (e.g. model incompatible with requested options).","solutions":["Read the detail suffix — Suno usually includes a reason (policy violation, rate limit, validation error).","For 429, wait and retry later; reduce generation frequency or batch size.","For 400, adjust the prompt or parameters (model, slider values) to valid combinations.","For 5xx, retry after a few minutes and check suno.com status — it's a server-side problem.","Confirm your session is fresh (run a session/status check) to rule out borderline auth states surfaced as other codes."],"exampleFix":"// before\nopencli suno generate --prompt \"...\" --weirdness 0.9 --model chirp-fenix   // HTTP 400 invalid params\n// after (use a valid parameter combination)\nopencli suno generate --prompt \"upbeat jazz\" --model chirp-v4 --weirdness 0.5","handlingStrategy":"retry","validationCode":"// Validate inputs before submission to avoid 400s\nif (!prompt || typeof prompt !== 'string') throw new Error('prompt required');\nif (!isSliderValue(weirdness) || !isSliderValue(styleWeight)) throw new Error('slider values must be 0..1');","typeGuard":"function isRetryableSunoFailure(err) {\n  const m = /Suno generate failed \\(HTTP (\\d+)\\)/.exec(err.message || '');\n  return !!m && ['429','500','502','503','504'].includes(m[1]);\n}","tryCatchPattern":"try {\n  await submitSunoGeneration(page, params);\n} catch (err) {\n  if (isRetryableSunoFailure(err)) {\n    await sleep(backoff); // retry 429/5xx with exponential backoff\n  } else if (/HTTP 4\\d\\d/.test(err.message)) {\n    console.error('Non-retryable request failure:', err.message); // fix params/prompt\n  } else throw err;\n}","preventionTips":["Only retry 429/5xx; treat 4xx as permanent and fix the request.","Respect Suno rate limits — space out generation calls.","Sanitize prompts against content-policy rejections.","Read the detail suffix in the message for the server's stated reason before retrying."],"tags":["suno","http-error","api","rate-limit"],"backgroundTag":"api-request-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}