{"record":{"id":"a271b2d5aaf891b2","repo":"yikart/AiToEarn","slug":"failed-to-create-generation-task","errorCode":null,"errorMessage":"Failed to create generation task","messagePattern":"Failed to create generation task","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"project/aitoearn-web/src/store/draft-box/planDetailStore.ts","lineNumber":611,"sourceCode":"              const resolvedAspectRatio = inputAspectRatio ?? aspectRatio\n              const res = await apiCreateDraftGeneration({\n                quantity,\n                groupId,\n                model: modelType,\n                duration: resolvedDuration,\n                resolution,\n                aspectRatio: resolvedAspectRatio,\n                prompt,\n                captionPrompt: captionPrompt || undefined,\n                imageUrls,\n                videoUrls,\n                audioUrls,\n                platforms: platforms?.length ? platforms : undefined,\n                draftType,\n              })\n\n              if (res?.code !== 0)\n                throw new Error(res?.message || 'Failed to create generation task')\n\n              return {\n                modelType,\n                resolution,\n                duration: resolvedDuration,\n                aspectRatio: resolvedAspectRatio,\n                taskIds: res.data?.taskIds || [],\n              }\n            }),\n          )\n\n          const fulfilled = results.filter(result => result.status === 'fulfilled')\n          const placeholders = results.flatMap((result) => {\n            if (result.status !== 'fulfilled')\n              return []\n            return result.value.taskIds.map((id: string) => buildDraftGenerationTaskPlaceholder(id, {\n              groupId,\n              model: result.value.modelType,","sourceCodeStart":593,"sourceCodeEnd":629,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-web/src/store/draft-box/planDetailStore.ts#L593-L629","documentation":"The draft-box plan detail store calls the backend video/audio generation-task API; any response with code !== 0 throws `new Error(res?.message || 'Failed to create generation task')`. Per project API convention, code 0 is success, so this is a backend-reported failure (auth, quota, invalid params, model unavailable) surfaced as a generic fallback message when the response has no message.","triggerScenarios":"Invoking the video generation action in planDetailStore where the create-task API returns { code: non-zero }, e.g. insufficient credits, invalid audioUrls/platforms/draftType params, expired token, or a malformed/empty response (message undefined falls back to the literal string).","commonSituations":"User submits AI video generation from a draft with an expired session; backend quota exhausted; model parameters (duration/aspectRatio/resolution) rejected; API gateway returns an error envelope without a message field.","solutions":["Inspect the actual res.code/res.message in the network tab to identify the backend cause (401 vs quota vs validation).","Refresh auth: re-login so the API returns code 0; 401-style codes are the most common trigger.","Validate request params before calling: ensure audioUrls is a non-empty array of valid URLs and draftType matches the endpoint's expectation.","Check account generation quota/credits on the backend if codes indicate limits.","Improve the fallback: surface res.message and code in the thrown error/UI instead of only the generic string."],"exampleFix":"// before\nif (res?.code !== 0)\n  throw new Error(res?.message || 'Failed to create generation task')\n\n// after\nif (res?.code !== 0)\n  throw new Error(`[${res?.code}] ${res?.message || 'Failed to create generation task'}`)","handlingStrategy":"validation","validationCode":"const params = { audioUrls, platforms, draftType }\nif (!audioUrls?.length) throw new Error('audioUrls is required')\nif (!draftType) throw new Error('draftType is required')\n// then check auth before calling\nconst authed = await ensureSessionValid() // re-login if expired","typeGuard":"interface ApiEnvelope<T> { code: number; message?: string; data?: T }\nfunction isApiSuccess<T>(res: ApiEnvelope<T> | undefined | null): res is ApiEnvelope<T> & { code: 0 } {\n  return !!res && res.code === 0\n}","tryCatchPattern":"try {\n  await createVideoTask(payload)\n}\ncatch (e) {\n  if (String(e.message).includes('401') || sessionExpired) return redirectToLogin()\n  toast.error(e.message || '创建生成任务失败')\n}","preventionTips":["Always check code === 0 before using res.data (project API convention)","Validate audioUrls/platforms/draftType against the endpoint contract before submit","Refresh tokens proactively; 401-style codes are the top trigger","Include res.code in thrown errors for actionable debugging","Check generation quota before enabling the generate button"],"tags":["api","backend","generation-task","draft-box"],"backgroundTag":"api-non-zero-code","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}