jackwener/OpenCLI · error · ArgumentError
clip-id required (UUID or /song/<id> URL)
Error message
clip-id required (UUID or /song/<id> URL)
What it means
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.
Source
Thrown at clis/suno/download.js:33
downloadSunoClip,
ensureSunoSession,
normalizeBooleanFlag,
parseFormats,
resolveSunoOutputDir,
unwrapEvaluateResult,
} from './utils.js';
import * as os from 'node:os';
function displayPath(filePath) {
if (!filePath) return '-';
const home = os.homedir();
return filePath.startsWith(home) ? `~${filePath.slice(home.length)}` : filePath;
}
function parseClipId(value) {
const raw = String(value || '').trim();
if (!raw) throw new ArgumentError('clip-id required (UUID or /song/<id> URL)');
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
if (uuidPattern.test(raw)) return raw.toLowerCase();
try {
const parsed = new URL(raw);
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);
if (parsed.protocol === 'https:' && parsed.hostname === 'suno.com' && pathMatch) {
return pathMatch[1].toLowerCase();
}
} catch {}
throw new ArgumentError(`Invalid clip-id: ${raw}`, 'Pass a UUID or a https://suno.com/song/<uuid> URL.');
}
export const downloadCommand = cli({
site: 'suno',
name: 'download',
access: 'write',
description: 'Download an existing Suno clip (MP3 + optional WAV/M4A/video) by id',
domain: SUNO_DOMAIN,View on GitHub (pinned to 49907e53dc)
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
Example fix
// before
const clip = process.env.CLIP_ID; // '' -> ArgumentError
await cli('suno', 'download', clip);
// after
if (!process.env.CLIP_ID) throw new Error('CLIP_ID is not set');
await cli('suno', 'download', process.env.CLIP_ID); Defensive patterns
Strategy: validation
Validate before calling
function requireClipId(value) {
const raw = String(value ?? '').trim();
if (!raw) throw new Error('clip-id required (UUID or /song/<id> URL)');
return raw;
}
requireClipId(process.argv[2]); Type guard
function hasClipId(v) { return typeof v === 'string' && v.trim().length > 0; } Try / catch
try {
await cli('suno', 'download', clipArg);
} catch (e) {
if (/clip-id required/.test(e.message)) {
console.error('Usage: opencli suno download <clip-uuid-or-url>');
process.exitCode = 2;
return;
}
throw e;
} Prevention
- 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
When it happens
Trigger: Running `opencli suno download` without the positional clip argument, or passing an empty/whitespace-only value (String(value||'').trim() yields '').
Common situations: 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.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- douyin delete aweme_id cannot be empty
- douyin delete aweme_id must be a numeric id
- eastmoney convertible --limit must be an integer between 1 a
- INVALID_ARGUMENT
- limit must be a positive integer ≤ ${max}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/71b3d0585ce3e137.
Report an issue: GitHub.