yikart/AiToEarn · error · Error

上传封面失败,失败原因:

Error message

上传封面失败,失败原因:

What it means

After uploading cover data, the service checks uploadPartRes.ETag; if absent it throws '上传封面失败,失败原因:' + X-Errno. Missing ETag means the server did not accept the part upload. Note a bug: the string concatenation binds before ||, so when X-Errno is missing the expression evaluates to the truthy prefix string and '未知错误' is never used.

Source

Thrown at project/aitoearn-electron/electron/plat/shipinhao/index.ts:845

      const uploadId = uploadIdRes.UploadID;

      // 开始上传
      const uploadPartRes = await this.uploadFile(
        this.uploadpartdfsUrl +
          `?UploadID=${uploadId}&PartNumber=1&QuickUpload=2`,
        fileData,
        {
          Authorization: uploadParams.authKey,
          'X-Arguments': uploadArgumentsString,
          'Content-Type': 'application/octet-stream',
        },
        undefined,
        proxy,
      );

      if (!uploadPartRes.ETag) {
        throw new Error(
          '上传封面失败,失败原因:' + uploadPartRes.data?.['X-Errno'] ||
            '未知错误',
        );
      }

      // 上传成功
      const uploadPartInfo = [
        {
          PartNumber: 1,
          ETag: uploadPartRes.ETag,
        },
      ];

      // 完成分片上传
      const uploadCompleteRes = await this.uploadFile(
        this.uploadCompleteUrl + `?UploadID=${uploadId}`,
        Buffer.from(
          JSON.stringify({

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Read the X-Errno value from the response data to identify the COS rejection reason.
  2. Re-request upload params and retry the cover upload from scratch.
  3. Validate the cover image file (exists, non-empty, correct format) before upload.
  4. Fix the operator-precedence bug so '未知错误' shows when X-Errno is absent: wrap the concatenation in parentheses.

Example fix

// before
throw new Error(
  '上传封面失败,失败原因:' + uploadPartRes.data?.['X-Errno'] ||
    '未知错误',
);
// after
throw new Error(
  '上传封面失败,失败原因:' + (uploadPartRes.data?.['X-Errno'] ?? '未知错误'),
);
Defensive patterns

Strategy: type-guard

Validate before calling

import fs from 'fs';
if (!fs.existsSync(coverPath) || fs.statSync(coverPath).size === 0) {
  throw new Error('invalid cover file');
}

Type guard

function hasETag(res: unknown): res is { ETag: string } {
  return typeof (res as any)?.ETag === 'string' && (res as any).ETag.length > 0;
}

Try / catch

try {
  await service.uploadCoverFile(/*...*/);
} catch (e) {
  if (e.message.includes('上传封面失败')) {
    const errno = e.message.split('失败原因:')[1];
    console.error('cover part upload rejected, X-Errno:', errno);
  }
}

Prevention

When it happens

Trigger: uploadCoverFile → part-upload (uploadFile) response without ETag: COS rejecting the chunk due to bad signature, wrong Content-MD5, session expiry, or an error body in data['X-Errno'].

Common situations: Expired upload session between apply and part upload, corrupted cover file bytes, proxy interrupting the PUT, or COS returning X-Errno (e.g. signature mismatch) instead of ETag.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/ca582252f244c6d2. Report an issue: GitHub.