{"record":{"id":"a823ae63945be4f8","repo":"yikart/AiToEarn","slug":"id","errorCode":null,"errorMessage":"上传视频失败,失败原因:获取上传id失败","messagePattern":"上传视频失败,失败原因:获取上传id失败","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"project/aitoearn-electron/electron/plat/shipinhao/index.ts","lineNumber":682,"sourceCode":"      const requestBody = {\n        BlockPartLength: filePartInfo.blockInfo,\n        BlockSum: filePartInfo.blockInfo.length,\n      };\n\n      const uploadIdRes = await this.uploadFile(\n        this.getApplyUploadDfsUrl,\n        Buffer.from(JSON.stringify(requestBody)),\n        {\n          Authorization: uploadParams.authKey,\n          'Content-Type': 'application/json',\n          'X-Arguments': uploadArgumentsString,\n        },\n        undefined,\n        proxy,\n      );\n\n      if (!uploadIdRes.UploadID) {\n        throw new Error('上传视频失败,失败原因:获取上传id失败');\n      }\n\n      const uploadId = uploadIdRes.UploadID;\n      const uploadPartInfo: any[] = [];\n\n      // 分片上传文件\n      for (let i = 0; i < filePartInfo.blockInfo.length; i++) {\n        let errorMsg = '';\n        const isSuccess = await RetryWhile(async () => {\n          if (this.callback)\n            this.callback(\n              50,\n              `上传视频（${i}/${filePartInfo.blockInfo.length}）`,\n            );\n          console.log(\n            `开始上传第 ${i + 1}/${filePartInfo.blockInfo.length} 个分片`,\n          );\n          const chunkStart = i === 0 ? 0 : filePartInfo.blockInfo[i - 1];","sourceCodeStart":664,"sourceCodeEnd":700,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/electron/plat/shipinhao/index.ts#L664-L700","documentation":"During video upload, ShipinhaoService first requests an UploadID from the Tencent COS upload endpoint. If the response has no UploadID field, this error is thrown, meaning the initial upload-session request failed before any file bytes were sent.","triggerScenarios":"uploadVideoFile → the apply-upload (get upload id) request returns a payload without UploadID: invalid/expired upload params, wrong file size/hash fields, server throttling, or the response being an error page parsed as an object.","commonSituations":"Stale upload params from a failed getPublishUploadParams, video file too large or zero bytes, COS endpoint rejecting due to signature/param mismatch, or rate limiting on the upload API.","solutions":["Re-fetch upload params via getPublishUploadParams with a fresh traceKey and retry.","Validate the video file exists, is non-empty, and matches declared size before uploading.","Log the full uploadIdRes payload — the server error field usually explains the rejection.","Retry after a delay; COS throttling typically returns a temporary error without an UploadID."],"exampleFix":"// before\nif (!uploadIdRes.UploadID) {\n  throw new Error('上传视频失败,失败原因:获取上传id失败');\n}\n// after\nif (!uploadIdRes.UploadID) {\n  console.error('applyUpload response:', JSON.stringify(uploadIdRes));\n  throw new Error(`上传视频失败,失败原因:获取上传id失败 ${JSON.stringify(uploadIdRes)}`);\n}","handlingStrategy":"validation","validationCode":"import fs from 'fs';\nconst stat = fs.statSync(videoPath);\nif (stat.size <= 0) throw new Error('video file is empty');\nif (!uploadParams) throw new Error('upload params missing — refetch first');","typeGuard":"function hasUploadId(res: unknown): res is { UploadID: string } {\n  return typeof (res as any)?.UploadID === 'string' && (res as any).UploadID.length > 0;\n}","tryCatchPattern":"try {\n  const url = await service.uploadVideoFile(/*...*/);\n} catch (e) {\n  if (e.message.includes('获取上传id失败')) {\n    // refetch upload params and retry the whole upload\n  }\n}","preventionTips":["Validate the video file exists and is non-empty before uploading","Always use freshly fetched upload params","Log the full apply-upload response to capture COS error codes","Add bounded retry with backoff for throttling"],"tags":["upload","shipinhao","cos","tencent"],"backgroundTag":"upload-id-missing","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}