{"record":{"id":"71b3d0585ce3e137","repo":"jackwener/OpenCLI","slug":"clip-id-required-uuid-or-song-id-url","errorCode":null,"errorMessage":"clip-id required (UUID or /song/<id> URL)","messagePattern":"clip-id required \\(UUID or /song/<id> URL\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/suno/download.js","lineNumber":33,"sourceCode":"    downloadSunoClip,\n    ensureSunoSession,\n    normalizeBooleanFlag,\n    parseFormats,\n    resolveSunoOutputDir,\n    unwrapEvaluateResult,\n} from './utils.js';\n\nimport * as os from 'node:os';\n\nfunction displayPath(filePath) {\n    if (!filePath) return '-';\n    const home = os.homedir();\n    return filePath.startsWith(home) ? `~${filePath.slice(home.length)}` : filePath;\n}\n\nfunction parseClipId(value) {\n    const raw = String(value || '').trim();\n    if (!raw) throw new ArgumentError('clip-id required (UUID or /song/<id> URL)');\n    const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n    if (uuidPattern.test(raw)) return raw.toLowerCase();\n    try {\n        const parsed = new URL(raw);\n        const pathMatch = parsed.pathname.match(/^\\/song\\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\/?$/i);\n        if (parsed.protocol === 'https:' && parsed.hostname === 'suno.com' && pathMatch) {\n            return pathMatch[1].toLowerCase();\n        }\n    } catch {}\n    throw new ArgumentError(`Invalid clip-id: ${raw}`, 'Pass a UUID or a https://suno.com/song/<uuid> URL.');\n}\n\nexport const downloadCommand = cli({\n    site: 'suno',\n    name: 'download',\n    access: 'write',\n    description: 'Download an existing Suno clip (MP3 + optional WAV/M4A/video) by id',\n    domain: SUNO_DOMAIN,","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/suno/download.js#L15-L51","documentation":"parseClipId() requires a non-empty clip id — either a raw UUID or a https://suno.com/song/<uuid> URL. Empty input (missing positional arg, empty string, null/undefined) throws this ArgumentError before any network call is made.","triggerScenarios":"Running `opencli suno download` without the positional clip argument, or passing an empty/whitespace-only value (String(value||'').trim() yields '').","commonSituations":"Scripting the CLI with a variable that is unset/empty because an earlier pipeline step produced no id; forgetting the positional arg entirely; shell quoting dropping the argument.","solutions":["Pass a clip UUID or a suno.com/song/<uuid> URL as the first positional argument","If the id comes from a previous command, verify that step actually emitted an id","Quote shell variables so an empty value doesn't silently disappear"],"exampleFix":"// before\nconst clip = process.env.CLIP_ID; // '' -> ArgumentError\nawait cli('suno', 'download', clip);\n// after\nif (!process.env.CLIP_ID) throw new Error('CLIP_ID is not set');\nawait cli('suno', 'download', process.env.CLIP_ID);","handlingStrategy":"validation","validationCode":"function requireClipId(value) {\n  const raw = String(value ?? '').trim();\n  if (!raw) throw new Error('clip-id required (UUID or /song/<id> URL)');\n  return raw;\n}\nrequireClipId(process.argv[2]);","typeGuard":"function hasClipId(v) { return typeof v === 'string' && v.trim().length > 0; }","tryCatchPattern":"try {\n  await cli('suno', 'download', clipArg);\n} catch (e) {\n  if (/clip-id required/.test(e.message)) {\n    console.error('Usage: opencli suno download <clip-uuid-or-url>');\n    process.exitCode = 2;\n    return;\n  }\n  throw e;\n}","preventionTips":["Always pass the positional clip argument explicitly","Validate upstream pipeline outputs are non-empty before invoking the CLI","Quote shell variables: \"$CLIP_ID\" so empty values fail loudly","Add a pre-flight check in scripts for required env/args"],"tags":["validation","argument","cli","suno"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}