{"record":{"id":"7c50c38e4dd77a4c","repo":"jackwener/OpenCLI","slug":"suno-generation-needs-a-resolved-plan-id-for-the-u","errorCode":null,"errorMessage":"Suno generation needs a resolved plan id for the user_tier field, but billing/info did not surface one for this account (subscription_type=${session.planKey}). Verify the account is active at ${SUNO_URL}/account, then retry.","messagePattern":"Suno generation needs a resolved plan id for the user_tier field, but billing/info did not surface one for this account \\(subscription_type=(.+?)\\)\\. Verify the account is active at (.+?)/account, then retry\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/suno/generate.js","lineNumber":124,"sourceCode":"            }\n            return true;\n        });\n        if (!skipDownload && !formats.length) {\n            throw new ArgumentError('All requested formats require --confirm-paid true', 'Add --confirm-paid true or include a free format such as mp3 or metadata.');\n        }\n        const outputDir = resolveSunoOutputDir(kwargs.op);\n        const timeout = requirePositiveInt(kwargs.timeout, '--timeout');\n        const makeInstrumental = normalizeBooleanFlag(kwargs.instrumental);\n        const weirdness = clampSlider(kwargs.weirdness, '--weirdness', 0.5);\n        const styleWeight = clampSlider(kwargs['style-weight'], '--style-weight', 0.5);\n\n        // Title: required by API. Auto-derive from first 60 chars of source prompt if not provided.\n        const titleSource = titleArg || (isCustom ? (tags || lyrics.split('\\n')[0]) : description);\n        const title = titleSource.replace(/\\s+/g, ' ').trim().slice(0, 60) || 'Untitled';\n\n        const session = await ensureSunoSession(page);\n        if (!session.planId) {\n            throw new CommandExecutionError(\n                `Suno generation needs a resolved plan id for the user_tier field, but billing/info did not surface one for this account (subscription_type=${session.planKey}). Verify the account is active at ${SUNO_URL}/account, then retry.`,\n            );\n        }\n        const deviceId = session.deviceId;\n        const captcha = await checkSunoCaptcha(page, deviceId);\n        if (!captcha?.ok) {\n            throw new CommandExecutionError(\n                `Suno captcha pre-flight failed${captcha?.status ? ` (HTTP ${captcha.status})` : ''}.`,\n                `Open ${SUNO_URL}/create in Chrome and verify the account is ready, then retry.`,\n            );\n        }\n        if (captcha?.required) {\n            throw new CommandExecutionError(\n                'Suno requires a CAPTCHA challenge for this account/IP right now.',\n                `Open ${SUNO_URL}/create in Chrome, solve a Create challenge once, then retry.`,\n            );\n        }\n        if (session.totalCreditsAvailable < 10) {","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/suno/generate.js#L106-L142","documentation":"A CommandExecutionError thrown after `ensureSunoSession(page)` when the session's billing/info response did not yield a `planId`. The generation API requires a `user_tier` field derived from the resolved plan id, so the CLI aborts instead of submitting a request with an undefined tier. `subscription_type=<planKey>` in the message shows the raw key Suno returned (which failed to map to a plan id).","triggerScenarios":"Running `opencli suno generate` with a logged-in Suno account whose billing/info response lacks a mappable plan — e.g. brand-new/free accounts with an unrecognized subscription_type string, Suno renaming plan keys, or a stale/soft-failing session where billing/info returns an unexpected body.","commonSituations":"Newly created Suno accounts, accounts mid-downgrade/expired subscription, Suno changing its subscription_type vocabulary after a product update, or an outdated CLI whose plan-key mapping predates Suno's current plan names.","solutions":["Verify the account is active and has an identifiable plan at https://suno.com/account, then retry the command.","Refresh the session: log out/in (or re-open suno.com in the driven Chrome profile) so billing/info returns fresh data, then retry.","Check the printed subscription_type value — if it's a new/unrecognized plan key, upgrade @jackwener/opencli so its plan mapping includes it.","If the account is fine and the CLI is current, file an issue with the subscription_type string from the message."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// verify the account has an active subscription before generating\n// open suno.com/account in the driven profile and confirm a plan is shown,\n// then retry; scripts can pre-check via the CLI session or billing/info response","typeGuard":"const sessionHasPlan = (session) =>\n  session != null && typeof session === 'object' &&\n  typeof session.planId === 'string' && session.planId.length > 0;","tryCatchPattern":"try {\n  await run('opencli suno generate \"...\"');\n} catch (err) {\n  if (String(err.message).includes('resolved plan id')) {\n    // re-login to suno.com, verify the account/plan, upgrade the CLI if\n    // subscription_type is a new key, then retry\n  } else throw err;\n}","preventionTips":["Confirm the Suno account is active with a visible plan at suno.com/account before automating generation.","Refresh the persistent session (re-login) after long idle periods or plan changes.","Update the CLI when Suno renames subscription tiers so plan-key mappings stay current."],"tags":["suno","session","billing","account-state"],"backgroundTag":"session-state-invalid","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}