{"record":{"id":"ca8c06cd5a7d360a","repo":"jackwener/OpenCLI","slug":"all-requested-formats-require-confirm-paid-true-ca8c06","errorCode":null,"errorMessage":"All requested formats require --confirm-paid true","messagePattern":"All requested formats require --confirm-paid true","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/suno/generate.js","lineNumber":110,"sourceCode":"        }\n        if (!isCustom && (tags || negativeTags)) {\n            throw new ArgumentError('--tags and --negative-tags only apply in Custom mode (alongside --lyrics).');\n        }\n\n        const requestedFormats = parseFormats(kwargs.formats);\n        const confirmPaid = normalizeBooleanFlag(kwargs['confirm-paid']);\n        const skipDownload = normalizeBooleanFlag(kwargs.sd);\n        const PAID_FORMATS = new Set(['wav']);\n        const skippedPaid = [];\n        const formats = requestedFormats.filter(f => {\n            if (PAID_FORMATS.has(f) && !confirmPaid) {\n                skippedPaid.push(f);\n                return false;\n            }\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;","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/suno/generate.js#L92-L128","documentation":"An ArgumentError thrown when every requested download format is a paid format (currently `wav`) and downloads are enabled but `--confirm-paid` was not set to true. WAV downloads trigger Suno's per-download billing, so the CLI strips paid formats and then refuses to run a download run with an empty free-format list rather than silently downloading nothing.","triggerScenarios":"Running `opencli suno generate \"...\" --formats wav` (or a formats list where all entries are paid) without `--confirm-paid true` and without `--sd true`. After the paid-format filter, `formats.length` is 0, so the guard fires.","commonSituations":"Users who want studio-quality WAV but don't realize it costs credits per download; CI scripts requesting only wav; misspelling free formats (e.g. `mp4` instead of `mp3`) leaving only paid entries after filtering.","solutions":["Add `--confirm-paid true` if you accept the per-download WAV billing charge.","Include a free format in --formats, e.g. `--formats mp3,metadata` or `--formats mp3,wav` (wav still requires confirm-paid).","Pass `--sd true` if you only want clip ids/URLs and no downloads at all.","Check for typos in format names — an unrecognized paid-looking list may filter down to zero free formats."],"exampleFix":"// before\nopencli suno generate \"epic rock\" --formats wav\n// after\nopencli suno generate \"epic rock\" --formats mp3,wav --confirm-paid true","handlingStrategy":"validation","validationCode":"// gate paid formats behind explicit consent before invoking\nconst PAID = new Set(['wav']);\nconst requested = (process.env.FORMATS ?? 'mp3,metadata').split(',').map(s => s.trim());\nconst needsPaid = requested.some(f => PAID.has(f));\nconst confirmPaid = process.env.CONFIRM_PAID === 'true';\nif (needsPaid && !confirmPaid) {\n  throw new Error('wav requires --confirm-paid true (per-download billing)');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await run('opencli suno generate \"...\" --formats wav');\n} catch (err) {\n  if (String(err.message).includes('confirm-paid')) {\n    // either add --confirm-paid true or include a free format like mp3/metadata\n  } else throw err;\n}","preventionTips":["Always include a free format (mp3, metadata) in --formats as a fallback.","Set --confirm-paid true deliberately and only when WAV billing is acceptable.","Use --sd true when you don't want downloads at all.","Double-check format names for typos before running."],"tags":["suno","cli","billing","argument-validation"],"backgroundTag":"billing-confirmation-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}