{"record":{"id":"c8114fc01ad6807f","repo":"jackwener/OpenCLI","slug":"suno-generation-returned-malformed-clips-payload","errorCode":null,"errorMessage":"Suno generation returned malformed clips payload.","messagePattern":"Suno generation returned malformed clips payload\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/suno/generate.js","lineNumber":170,"sourceCode":"        const submission = await submitSunoGeneration(page, {\n            mode: isCustom ? 'custom' : 'simple',\n            model,\n            title,\n            lyrics,\n            tags,\n            negativeTags,\n            description,\n            makeInstrumental,\n            weirdness,\n            styleWeight,\n            userTier: session.planId,\n            createSessionToken,\n            transactionUuid,\n            deviceId,\n        });\n\n        if (!Array.isArray(submission.clips)) {\n            throw new CommandExecutionError('Suno generation returned malformed clips payload.');\n        }\n        const clipIds = submission.clips.map(c => c?.id);\n        if (clipIds.some(id => !id)) {\n            throw new CommandExecutionError('Suno generation returned malformed clip identity.');\n        }\n        if (!clipIds.length) {\n            throw new CommandExecutionError('Suno accepted the request but returned no clip ids.');\n        }\n\n        const clips = await pollSunoClips(page, clipIds, timeout, deviceId);\n        const completed = clips.filter(c => c.status === 'complete');\n        if (!completed.length) {\n            const errors = clips.map(c => `${c.id.slice(0, 8)}:${c.status}`).join(', ');\n            throw new CommandExecutionError(`All Suno clips failed (${errors}). Open ${SUNO_URL}/song/${clipIds[0]} to inspect.`);\n        }\n\n        const rows = [];\n        for (const clip of clips) {","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/suno/generate.js#L152-L188","documentation":"After submitting, the CLI validates that `submission.clips` is an array. If Suno's /api/generate response lacks a clips array (unexpected shape, auth payload, or error body), this CommandExecutionError is thrown instead of failing later with a confusing TypeError.","triggerScenarios":"`submitSunoGeneration()` returns an object whose `clips` field is not an array — e.g. Suno returned an error envelope, HTML, or a schema drift in the v2-web generate endpoint.","commonSituations":"Suno API contract change after a site update, session silently expired so an auth error JSON was returned, or the in-page fetch was intercepted by a bot-protection response.","solutions":["Log/inspect the full submission payload to see what Suno actually returned.","Re-login in the browser profile to refresh cookies and Clerk session token, then retry.","Check if Suno changed the /api/generate/v2-web/ response schema and update the CLI parsing.","Retry later — a transient Suno incident may be returning error bodies."],"exampleFix":"// before: assumes clips exists\nconst ids = submission.clips.map(c => c.id);\n// after: validate first\nif (!Array.isArray(submission?.clips)) throw new Error('malformed clips payload: ' + JSON.stringify(submission).slice(0, 500));\nconst ids = submission.clips.map(c => c?.id);","handlingStrategy":"type-guard","validationCode":"const submission = await submitSunoGeneration(page, params);\nif (!submission || typeof submission !== 'object') throw new Error('generate returned non-object');\nif (!Array.isArray(submission.clips)) throw new Error('no clips array: ' + JSON.stringify(submission).slice(0, 500));","typeGuard":"function isClipsPayload(v) { return !!v && typeof v === 'object' && Array.isArray(v.clips); }","tryCatchPattern":"try {\n  const submission = await submitSunoGeneration(page, params);\n  if (!isClipsPayload(submission)) throw new Error('Suno API schema drift — inspect raw payload');\n} catch (e) {\n  logger.error({ payload: e.submission }, 'suno generate payload invalid');\n  throw e;\n}","preventionTips":["Log the raw generate response on every failure for debugging.","Pin/monitor Suno API contract changes after site updates.","Re-authenticate sessions so error envelopes aren't mistaken for success payloads.","Add a schema test against a recorded successful response."],"tags":["api-contract","schema-validation","browser-automation"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}