{"record":{"id":"45a52676486b3557","repo":"yikart/AiToEarn","slug":"2","errorCode":null,"errorMessage":"上传视频失败,失败原因2:合并分片失败","messagePattern":"上传视频失败,失败原因2:合并分片失败","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"project/aitoearn-electron/electron/plat/shipinhao/index.ts","lineNumber":761,"sourceCode":"      const completeBody = {\n        TransFlag: '0_0',\n        PartInfo: uploadPartInfo,\n      };\n\n      const uploadCompleteRes = await this.uploadFile(\n        this.uploadCompleteUrl + `?UploadID=${uploadId}`,\n        Buffer.from(JSON.stringify(completeBody)),\n        {\n          Authorization: uploadParams.authKey,\n          'Content-Type': 'application/json',\n          'X-Arguments': uploadArgumentsString,\n        },\n        undefined,\n        proxy,\n      );\n\n      if (!uploadCompleteRes.DownloadURL) {\n        throw new Error('上传视频失败,失败原因2:合并分片失败');\n      }\n\n      return uploadCompleteRes.DownloadURL.replace(\n        'http://wxapp.tc.qq.com',\n        'https://finder.video.qq.com',\n      );\n    } catch (err: any) {\n      const errorMessage = err?.message || err || '未知';\n      throw new Error('上传视频失败,失败原因1:' + errorMessage);\n    }\n  }\n\n  /**\n   * 上传封面文件\n   * @param filePath\n   * @param uploadParams\n   */\n  private async uploadCoverFile(","sourceCodeStart":743,"sourceCodeEnd":779,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/electron/plat/shipinhao/index.ts#L743-L779","documentation":"After all video chunks are uploaded, ShipinhaoService calls the complete/merge endpoint and expects a DownloadURL in the response. If it is missing, the multipart merge failed on the server side and this error is thrown. The upload never produced a usable remote video URL.","triggerScenarios":"uploadVideoFile → complete-upload request returns a payload without DownloadURL: one or more parts failed integrity checks (bad ETag/MD5), not all parts were uploaded, or the COS complete call was rejected (signature/session expired mid-upload).","commonSituations":"Network interruption during part uploads leaving the merge with missing parts, very large videos timing out, session expiry between part uploads and the complete call, or COS returning an error body without DownloadURL.","solutions":["Re-run the whole uploadVideoFile flow with fresh upload params; partial merges cannot be resumed here.","Verify every part upload returned an ETag and record parts correctly before calling complete.","Check network stability (especially through proxy) during chunk uploads.","Inspect uploadCompleteRes body for a COS error code (e.g. NoSuchUpload, InvalidPart) and fix accordingly."],"exampleFix":"null","handlingStrategy":"retry","validationCode":"// confirm every part reported an ETag before calling complete\nif (uploadPartInfo.some(p => !p.ETag)) {\n  throw new Error('some parts missing ETag — redo part uploads');\n}","typeGuard":"function hasDownloadUrl(res: unknown): res is { DownloadURL: string } {\n  return typeof (res as any)?.DownloadURL === 'string' && (res as any).DownloadURL.length > 0;\n}","tryCatchPattern":"try {\n  const url = await service.uploadVideoFile(/*...*/);\n} catch (e) {\n  if (e.message.includes('合并分片失败')) {\n    // restart upload with fresh params; merge failures are not resumable here\n  }\n}","preventionTips":["Track ETag for every uploaded part and verify before complete","Keep the network stable during large multipart uploads (avoid flaky proxies)","Complete the merge promptly to avoid UploadID/session expiry","Retry the entire upload on merge failure rather than resuming"],"tags":["upload","shipinhao","multipart","cos"],"backgroundTag":"multipart-upload-complete-failed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}