{"record":{"id":"508b7d357411a08e","repo":"jeecgboot/JeecgBoot","slug":"error-508b7d","errorCode":null,"errorMessage":"提交任务失败","messagePattern":"提交任务失败","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"jeecgboot-vue3/src/views/super/airag/aivideo2/AiVideo.vue","lineNumber":170,"sourceCode":"      generating.value = true;\n      videoUrl.value = '';\n      errorMessage.value = '';\n      elapsedSeconds.value = 0;\n      statusText.value = '任务已提交，排队中...';\n\n      // 启动计时器\n      elapsedTimer = setInterval(() => {\n        elapsedSeconds.value++;\n      }, 1000);\n\n      // 提交任务\n      const submitResult = await submitVideoTask({\n        prompt: values.prompt.trim(),\n        category: activeCategory.value,\n      });\n\n      if (!submitResult || !submitResult.taskId) {\n        throw new Error(submitResult?.message || '提交任务失败');\n      }\n\n      statusText.value = '视频生成中...';\n\n      // 开始轮询\n      pollTimer = setInterval(async () => {\n        try {\n          const queryResult = await queryVideoTask(submitResult.taskId);\n          if (queryResult.status === 'SUCCESS') {\n            clearTimers();\n            generating.value = false;\n            videoUrl.value = queryResult.videoUrl;\n            createMessage.success('视频生成成功！');\n          } else if (queryResult.status === 'FAIL') {\n            clearTimers();\n            generating.value = false;\n            errorMessage.value = queryResult.message || '视频生成失败';\n          }","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecgboot-vue3/src/views/super/airag/aivideo2/AiVideo.vue#L152-L188","documentation":"In `handleGenerate`, after `submitVideoTask` resolves the code requires the response to be truthy AND contain a `taskId`; otherwise it throws the server `message` or the generic `提交任务失败`. This protects the subsequent polling loop (`queryVideoTask(submitResult.taskId)`) from polling an undefined id.","triggerScenarios":"`submitVideoTask` returns `null`/`undefined` (backend returned success with empty body), returns an object lacking `taskId`, or the HTTP layer normalized a non-200 into a falsy payload. Also fires when the backend replies `{ message: '...' }` with no `taskId` (quota exceeded, content filter, model not configured).","commonSituations":"The airag video backend is down or mis-configured; the prompt tripped content moderation; the API contract changed and `taskId` was renamed (e.g. `id`, `task_id`); the auth token expired so the interceptor returned an error object without `taskId`; rate-limit response.","solutions":["Inspect the submit endpoint response in the browser network tab — confirm HTTP 200 and the exact field name carrying the task id.","If the field differs, align the check with the real contract (e.g. `submitResult?.data?.task_id`).","Check the airag backend logs for why the task was rejected (quota, filter, missing model config).","Verify the bearer token is present (defHttp attaches it) and not expired."],"exampleFix":"// before\nif (!submitResult || !submitResult.taskId) {\n  throw new Error(submitResult?.message || '提交任务失败');\n}\n\n// after — surface the real response so the failure is diagnosable\nif (!submitResult?.taskId) {\n  const reason = submitResult?.message || JSON.stringify(submitResult) || 'empty response';\n  throw new Error(`提交任务失败: ${reason}`);\n}","handlingStrategy":"validation","validationCode":"// validate the submit response shape before relying on taskId\nconst submitResult = await submitVideoTask({ prompt: values.prompt.trim(), category: activeCategory.value });\nconst taskId = submitResult?.taskId ?? submitResult?.data?.task_id; // tolerant to either contract\nif (!taskId) {\n  errorMessage.value = submitResult?.message || '提交任务失败';\n  return;\n}","typeGuard":"const isVideoTaskResult = (r: unknown): r is { taskId: string } =>\n  typeof r === 'object' && r !== null && typeof (r as any).taskId === 'string' && (r as any).taskId.length > 0;","tryCatchPattern":"// keep the single outer try/catch in handleGenerate; just feed it a precise message\ntry {\n  const submitResult = await submitVideoTask(/* ... */);\n  if (!isVideoTaskResult(submitResult)) {\n    throw new Error(`提交任务失败: ${submitResult?.message || JSON.stringify(submitResult) || 'no taskId'}`);\n  }\n  // ...poll\n} catch (error: any) {\n  clearTimers();\n  generating.value = false;\n  errorMessage.value = error?.message || '提交任务失败';\n}","preventionTips":["Define and share a TypeScript interface for the submit response across FE/BE.","Assert the response shape with a type guard before using taskId.","Add an integration test that confirms the backend returns taskId on success.","Log the raw submit response on failure so contract drift is visible."],"tags":["vue3","airag","ai-video","api-contract","async","typescript"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}