{"record":{"id":"3c5e836d8ecd2119","repo":"jackwener/OpenCLI","slug":"unsupported-formats-value-s-unknown-join","errorCode":null,"errorMessage":"Unsupported --formats value(s): ${unknown.join(', ')}","messagePattern":"Unsupported --formats value\\(s\\): (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/suno/utils.js","lineNumber":42,"sourceCode":"export const STUDIO_API = 'https://studio-api-prod.suno.com';\nexport const SUNO_CDN = 'https://cdn1.suno.ai';\n\n// As of 2026-05, the UI exposes V5.5 (chirp-fenix) and V4.5+ (chirp-bluejay).\n// Older versions are still routable via the API and remain valid `mv` values.\nexport const SUNO_MODELS = ['chirp-fenix', 'chirp-bluejay', 'chirp-v4', 'chirp-v3-5'];\nexport const DEFAULT_SUNO_MODEL = 'chirp-fenix';\n\nexport const SUPPORTED_FORMATS = ['mp3', 'm4a', 'wav', 'video', 'cover', 'metadata'];\nexport const DEFAULT_FORMATS = ['mp3', 'metadata'];\n\nexport function parseFormats(value) {\n    if (value === undefined || value === null || value === '') return DEFAULT_FORMATS.slice();\n    const raw = Array.isArray(value) ? value.join(',') : String(value);\n    const parts = raw.split(',').map(s => s.trim().toLowerCase()).filter(Boolean);\n    if (!parts.length) return DEFAULT_FORMATS.slice();\n    const unknown = parts.filter(p => !SUPPORTED_FORMATS.includes(p));\n    if (unknown.length) {\n        throw new ArgumentError(\n            `Unsupported --formats value(s): ${unknown.join(', ')}`,\n            `Supported: ${SUPPORTED_FORMATS.join(', ')}. (stems require multi-step extraction and are not yet wired.)`,\n        );\n    }\n    return Array.from(new Set(parts));\n}\n\nexport function resolveSunoOutputDir(value) {\n    const raw = String(value || '').trim();\n    if (!raw) return path.join(process.env.HOME || '~', 'Music', 'suno');\n    if (raw === '~') return process.env.HOME || '~';\n    if (raw.startsWith('~/')) return path.join(process.env.HOME || '~', raw.slice(2));\n    return path.resolve(raw);\n}\n\nexport function sanitizeTitleForFilename(title, fallback = 'untitled') {\n    const cleaned = String(title || fallback)\n        .replace(/[\\\\/:*?\"<>|\\x00-\\x1f]+/g, '-')","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/suno/utils.js#L24-L60","documentation":"parseFormats validates the `--formats` flag against a whitelist (mp3, m4a, wav, video, cover, metadata). Any value outside SUPPORTED_FORMATS raises ArgumentError listing the rejected values plus the supported set. Stems are explicitly not supported yet because they need multi-step extraction.","triggerScenarios":"Passing `--formats` with a value not in ['mp3','m4a','wav','video','cover','metadata'] — e.g. `--formats stems`, `--formats flac`, a typo like `--formats mp4`, or a comma list where at least one token is unknown. Values are trimmed and lowercased first, so 'MP3' is fine.","commonSituations":"Assuming stems download is supported; typing 'mp4' instead of 'video'; using format names from another tool (flac, ogg); passing a comma list with one bad token which fails the whole list.","solutions":["Replace the unsupported value with one from the whitelist: mp3, m4a, wav, video, cover, metadata.","Check the error's second line — it prints the currently supported set.","Remove 'stems' from the list; stem extraction is not wired yet in this CLI version.","Update the CLI if you believe a format should be supported — newer versions may extend SUPPORTED_FORMATS."],"exampleFix":"// before\nsuno generate --prompt \"song\" --formats mp3,stems\n// after\nsuno generate --prompt \"song\" --formats mp3,m4a","handlingStrategy":"validation","validationCode":"const SUPPORTED = ['mp3','m4a','wav','video','cover','metadata'];\nconst requested = String(formats || '').split(',').map(s => s.trim().toLowerCase()).filter(Boolean);\nconst bad = requested.filter(f => !SUPPORTED.includes(f));\nif (bad.length) throw new Error(`Unsupported formats: ${bad.join(', ')}. Supported: ${SUPPORTED.join(', ')}`);","typeGuard":"function isSupportedFormat(f) {\n  return ['mp3','m4a','wav','video','cover','metadata'].includes(f);\n}","tryCatchPattern":"try {\n  await run({ formats: parseFormats(userFormats) });\n} catch (err) {\n  if (err.name === 'ArgumentError' && /Unsupported --formats/.test(err.message)) {\n    console.warn('Falling back to default formats: mp3,metadata');\n  } else throw err;\n}","preventionTips":["Only use whitelisted format names: mp3, m4a, wav, video, cover, metadata.","Do not request 'stems' — unsupported by design.","Normalize case/whitespace before passing the flag.","Reuse parseFormats() in scripts instead of hand-building format lists."],"tags":["cli","argument-validation","suno","formats"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}