{"record":{"id":"4d6a56b9e443d361","repo":"jackwener/OpenCLI","slug":"suno-download-wrote-no-files-for-clip-clip-id","errorCode":null,"errorMessage":"Suno download wrote no files for clip ${clip.id}","messagePattern":"Suno download wrote no files for clip (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/suno/generate.js","lineNumber":212,"sourceCode":"                    title: clip.title || '(untitled)',\n                    files: '-',\n                    link: `🔗 ${link}`,\n                });\n                continue;\n            }\n            if (skipDownload) {\n                rows.push({\n                    status: '🎵 generated',\n                    clip: clip.id.slice(0, 8),\n                    title: clip.title || '(untitled)',\n                    files: '📁 -',\n                    link: `🔗 ${link}`,\n                });\n                continue;\n            }\n            const result = await downloadSunoClip(page, clip, outputDir, formats, deviceId);\n            if (!result.written.some(w => w.ok)) {\n                throw new CommandExecutionError(`Suno download wrote no files for clip ${clip.id}`);\n            }\n            const writtenSummary = result.written\n                .map(w => w.ok ? `${w.format}:${displayPath(w.file)}` : `${w.format}:✗(${w.reason})`)\n                .join(' | ');\n            const skippedSummary = skippedPaid.length\n                ? ` | skipped(needs --confirm-paid):${skippedPaid.join(',')}`\n                : '';\n            const anyFailed = result.written.some(w => !w.ok);\n            rows.push({\n                status: anyFailed ? '⚠ partial' : '✅ saved',\n                clip: clip.id.slice(0, 8),\n                title: clip.title || '(untitled)',\n                files: `📁 ${writtenSummary}${skippedSummary}`,\n                link: `🔗 ${link}`,\n            });\n        }\n        return rows;\n    },","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/suno/generate.js#L194-L230","documentation":"For each completed clip, `downloadSunoClip()` attempts every requested format; if not a single file was written successfully (all writes failed), the CLI throws. This guarantees the command never silently reports success with zero downloaded files.","triggerScenarios":"`result.written.every(w => !w.ok)` for a completed clip — every requested format failed to download (auth expired, audio URL 403/404, disk error, or only paid formats requested without --confirm-paid so nothing was attempted).","commonSituations":"CDN audio URLs expired before download, cookies lost mid-run, output directory not writable, or requesting wav (paid) without --confirm-paid so formats list became empty of downloadable media.","solutions":["Re-run and pass free formats explicitly, e.g. --formats mp3,metadata (wav requires --confirm-paid true).","Verify cookies/session are still valid and re-login if audio asset requests return 401/403.","Check the output directory (-p/--op) exists and is writable.","Retry shortly after generation so the CDN URLs haven't expired; report failures per format shown as ✗(reason)."],"exampleFix":"// before: wav only, silently filtered out without --confirm-paid\n$ opencli suno generate \"beat\" --formats wav\n// after\n$ opencli suno generate \"beat\" --formats mp3,metadata\n// or allow paid: --formats wav --confirm-paid true","handlingStrategy":"validation","validationCode":"// Ensure at least one free, downloadable format is requested:\nconst formats = parseFormats(kwargs.formats).filter(f => f !== 'wav' || confirmPaid);\nif (!skipDownload && !formats.some(f => ['mp3', 'm4a', 'metadata'].includes(f))) {\n  throw new Error('add a free format (mp3/metadata) or pass --confirm-paid true');\n}\n// and verify the output dir is writable:\nawait fs.promises.access(outputDir, fs.constants.W_OK);","typeGuard":"function hasWrittenFile(result) { return Array.isArray(result?.written) && result.written.some(w => w?.ok === true); }","tryCatchPattern":"try {\n  const rows = await opencli('suno', 'generate', prompt, '--formats', 'mp3,metadata');\n} catch (e) {\n  if (/wrote no files for clip/.test(e.message)) {\n    await reloginIfCookiesExpired();\n    await retryDownloadSoon(clipId); // retry before CDN URLs expire\n  } else throw e;\n}","preventionTips":["Always include mp3 or metadata in --formats; reserve wav for --confirm-paid true.","Verify the -p/--op output directory exists and is writable before long jobs.","Download promptly after generation so CDN URLs don't expire.","Watch per-format ✗(reason) summaries to catch auth or disk issues early."],"tags":["download","filesystem","auth"],"backgroundTag":"download-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}