{"record":{"id":"a9dd7be1f73f8331","repo":"jackwener/OpenCLI","slug":"suno-api-rejected-request-http-status-re-log","errorCode":null,"errorMessage":"Suno API rejected request (HTTP ${status}). Re-login on suno.com.","messagePattern":"Suno API rejected request \\(HTTP (.+?)\\)\\. Re-login on suno\\.com\\.","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":401,"severity":"error","filePath":"clis/suno/utils.js","lineNumber":332,"sourceCode":"    const bodyJson = JSON.stringify(body);\n    const deviceId = payload.deviceId;\n    const result = unwrapEvaluateResult(await page.evaluate(`(async () => {\n        const res = await fetch('${STUDIO_API}/api/generate/v2-web/', {\n            method: 'POST',\n            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// ─────────────────────────────────────────────────────────────────────────────","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/suno/utils.js#L314-L350","documentation":"submitSunoGeneration posts to Suno's /api/generate/v2-web/ endpoint; when the API responds 401 or 403 it throws AuthRequiredError with this message, meaning your Clerk bearer JWT is no longer accepted. The CLI deliberately routes these statuses to the auth-recovery path rather than reporting a generic failure.","triggerScenarios":"Calling a generate/submission flow while logged out or with an expired Clerk session token; Suno rejecting the JWT (revoked session, token refresh failure in the page context, or server-side session invalidation).","commonSituations":"JWT expired during a long session; user signed out or changed password in the browser; suno.com rotating auth and invalidating old tokens; clock skew in the browser-token anti-replay header combined with auth checks.","solutions":["Open https://suno.com in the Chrome profile the CLI drives and re-login, then retry the generation.","Ensure the session pre-flight (suno status / session check) passes before generating.","Clear suno.com cookies if re-login alone doesn't refresh the Clerk token, then sign in again.","Check you haven't signed in on a different browser than the automation target.","Update the CLI if 401/403 persist after fresh login — Suno may have changed the auth schema."],"exampleFix":"// before\nopencli suno generate --prompt \"song\"   // HTTP 401 -> AuthRequiredError\n// after (re-login in the automated Chrome first)\n// 1. sign in at https://suno.com\nopencli suno generate --prompt \"song\"","handlingStrategy":"try-catch","validationCode":"// Refresh session before generation\nconst session = await ensureSunoSession(page, deviceId); // throws AuthRequiredError early if logged out\nif (!session.ok) throw new Error('Sign in to suno.com before generating');","typeGuard":"function isSunoAuthError(err) {\n  return err instanceof AuthRequiredError || /rejected request \\(HTTP (401|403)\\)/.test(err.message || '');\n}","tryCatchPattern":"try {\n  await submitSunoGeneration(page, params);\n} catch (err) {\n  if (isSunoAuthError(err)) {\n    console.error('Re-login on suno.com, then retry.');\n    process.exitCode = 2;\n  } else throw err;\n}","preventionTips":["Run the session pre-flight before each generation batch.","Re-login whenever the JWT may have expired (long-running sessions).","Keep a single signed-in profile; don't switch browsers mid-flow.","Catch AuthRequiredError distinctly from other CommandExecutionErrors to trigger a re-login prompt."],"tags":["auth","suno","http-401","http-403","jwt"],"backgroundTag":"auth-session-expired","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}