{"record":{"id":"680f30c4de8bc9e5","repo":"jackwener/OpenCLI","slug":"suno-generation-did-not-complete-within-timeouts","errorCode":null,"errorMessage":"Suno generation did not complete within ${timeoutSeconds}s. Try --timeout <higher>.","messagePattern":"Suno generation did not complete within (.+?)s\\. Try --timeout <higher>\\.","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"clis/suno/utils.js","lineNumber":399,"sourceCode":"            throw new CommandExecutionError('Suno feed API returned malformed JSON while polling clips');\n        }\n\n        const allClips = result.body.clips || [];\n        if (!Array.isArray(allClips)) {\n            throw new CommandExecutionError('Suno feed API returned malformed clips payload');\n        }\n        const ourClips = allClips.filter(c => targetSet.has(c.id));\n        const finished = ourClips.filter(c => c.status === 'complete' || c.status === 'error');\n\n        if (typeof onProgress === 'function') {\n            onProgress({ total: clipIds.length, done: finished.length, statuses: ourClips.map(c => `${c.id.slice(0,8)}:${c.status}`) });\n        }\n\n        if (finished.length === clipIds.length) return ourClips;\n        await page.wait(pollSeconds);\n    }\n\n    throw new TimeoutError(`Suno generation did not complete within ${timeoutSeconds}s. Try --timeout <higher>.`);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Asset download.\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction pickMediaUrl(clip, contentTypeFragment) {\n    const arr = Array.isArray(clip.media_urls) ? clip.media_urls : [];\n    const hit = arr.find(m => (m.content_type || '').toLowerCase().includes(contentTypeFragment));\n    return hit?.url || null;\n}\n\n/**\n * Resolve the canonical MP3 URL for a clip. Suno's /api/download/clip/{id}\n * returns a fresh signed URL; clip.audio_url is a backup.\n */\nasync function resolveMp3Url(page, clip, deviceId) {\n    const fromApi = await page.evaluate(`(async () => {","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/suno/utils.js#L381-L417","documentation":"pollSunoClips loops until every requested clip id reaches status 'complete' or 'error', or the timeout deadline passes. If the deadline expires first, TimeoutError is thrown, suggesting a higher --timeout.","triggerScenarios":"Within timeoutSeconds, at least one requested clip never reports complete/error via /api/feed/v3 — generation still queued/processing, a clip stuck in a nonterminal status, or the clip id never appearing in the feed.","commonSituations":"Long songs or high queue load during peak hours; very low --timeout (default too short for batch requests); Suno outage leaving generations pending indefinitely; invalid clip ids that never show in feed.","solutions":["Re-run with a higher --timeout (e.g. --timeout 600).","Check suno.com library page — the clip may have completed after the CLI gave up.","Increase pollSeconds slightly and retry during off-peak hours if the queue is congested.","Verify the clip ids are valid; ids absent from the feed will never satisfy the completion check."],"exampleFix":"// before\nawait pollSunoClips(page, ids, 120, deviceId);\n// after\nawait pollSunoClips(page, ids, 600, deviceId); // or CLI: --timeout 600","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const clips = await pollSunoClips(page, ids, 300, deviceId);\n} catch (e) {\n  if (e instanceof TimeoutError) {\n    // fall back to checking the clips later or with a longer timeout\n    console.warn('Generation still pending; retry with --timeout 600 or check suno.com library');\n  } else throw e;\n}","preventionTips":["Set --timeout generously (>= 300s) for batch or long generations","Expect longer queues at peak hours; raise timeout accordingly","Verify clip ids are valid before polling"],"tags":["timeout","suno","polling","async"],"backgroundTag":"polling-timeout","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}