jackwener/OpenCLI · error · ArgumentError
Invalid clip-id: ${raw}
Error message
Invalid clip-id: ${raw} What it means
parseClipId() accepts either a bare UUID (case-insensitive hex pattern) or an exact https://suno.com/song/<uuid> URL. Anything else — malformed UUID, wrong hostname/path, non-https URL, or unparseable string — throws ArgumentError with the offending value and a hint about the accepted formats.
Source
Thrown at clis/suno/download.js:43
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,
strategy: Strategy.COOKIE,
browser: true,
siteSession: 'persistent',
navigateBefore: false,
defaultFormat: 'plain',
args: [
{ name: 'clip', positional: true, required: true, help: 'Clip UUID or https://suno.com/song/<id> URL' },
{ name: 'formats', help: 'Comma-separated formats: mp3, m4a, wav, video, cover, metadata. Default: mp3,metadata' },
{ name: 'op', help: 'Output directory (default: ~/Music/suno)' },
{ name: 'confirm-paid', type: 'boolean', default: false, help: 'Required to allow paid downloads (wav). Without it, paid formats are skipped with a warning.' },View on GitHub (pinned to 49907e53dc)
Solutions
- Use the canonical https://suno.com/song/<uuid> URL (strip query strings) or just the UUID
- Extract the UUID from a longer URL manually and pass the UUID alone
- Note www.suno.com and non-https variants are rejected — use https://suno.com exactly
Example fix
// before
await cli('suno', 'download', 'https://suno.com/song/abc123?utm=x');
// -> ArgumentError: Invalid clip-id
// after
const m = url.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i);
await cli('suno', 'download', m[0]); Defensive patterns
Strategy: validation
Validate before calling
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
function extractClipId(input) {
const raw = String(input || '').trim();
if (UUID.test(raw)) return raw.toLowerCase();
const m = raw.match(/https:\/\/suno\.com\/song\/([0-9a-f-]{36})/i);
if (m) return m[1].toLowerCase();
throw new Error(`Not a valid clip id: ${raw}`);
} Type guard
function isValidClipId(v) {
return typeof v === 'string' &&
(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v.trim()) ||
/^https:\/\/suno\.com\/song\/[0-9a-f-]{36}\/?$/i.test(v.trim()));
} Try / catch
try {
await cli('suno', 'download', clipInput);
} catch (e) {
if (/Invalid clip-id/.test(e.message)) {
const uuid = clipInput.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i);
if (uuid) return cli('suno', 'download', uuid[0].toLowerCase());
}
throw e;
} Prevention
- Normalize share links: strip query strings before passing URLs
- Use the canonical https://suno.com/song/<uuid> form (no www, no http)
- Extract UUIDs with a regex when handling arbitrary pasted links
- Store bare UUIDs in scripts instead of full URLs
When it happens
Trigger: Passing a full song page URL with extra path/query (e.g. ?shuffle=true), an http:// URL, a suno.org or www hostname, a truncated id, or an internal numeric id instead of the UUID.
Common situations: Copying a share link with tracking query params; using the song's slug URL (/song/title-slug) instead of the canonical UUID URL; pasting an embed URL; old bookmark with a different domain.
Related errors
- clip-id required (UUID or /song/<id> URL)
- Invalid tweet URL: ${value}
- Invalid tweet URL host: ${value}
- bbc topic "${args.topic}" is not supported
- bbc ${label} must be a positive integer
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/15f601c6029c12cf.
Report an issue: GitHub.