transloadit/uppy · error · Error

Failed to complete multipart upload

Error message

${C.ERROR_PREFIX}Failed to complete multipart upload: ${JSON.stringify(parsed)}

What it means

completeMultipartUpload's fallback throw: the response was parsed but matched none of the expected success shapes (no Location/Key result, no recognizable error), so the client cannot determine the outcome of the completion request.

Solutions

  1. Log the parsed payload to see what the endpoint actually returned
  2. Retry the operation — the upload may or may not have completed; call listParts to check whether uploadId still exists (NoSuchUpload means it completed)
  3. Verify S3 compatibility of the endpoint or upgrade @uppy/aws-s3 for endpoint-specific fixes
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

null

Try / catch

try { await complete(...) } catch (e) { const exists = await listParts(...).then(() => true, () => false); if (!exists) return /* already completed */; throw e }

Prevention

When it happens

Trigger: S3 returns a 2xx with an empty or unexpected body for CompleteMultipartUpload; a non-S3-compatible server returns HTML/JSON instead of the expected XML.

Common situations: Using S3-compatible third-party storage (MinIO, R2, custom proxies) whose completion response differs; network middlewares truncating responses.

Related errors


AI-assisted analysis of transloadit/uppy@5d4dedd02a (2026-08-28). Data as JSON: /api/errors/ffcd43b683a54653. Report an issue: GitHub.

Appendix: source

Thrown at packages/@uppy/aws-s3/src/s3-client/S3mini.ts:468

        if (!resultLocation || !resultKey) {
          throw new Error(
            `${C.ERROR_PREFIX}CompleteMultipartUpload response missing Location or Key: ${JSON.stringify(r)}`,
          )
        }

        const etag = rawEtag ? U.sanitizeXmlETag(rawEtag) : undefined

        return {
          location: resultLocation,
          bucket: resultBucket,
          key: resultKey,
          etag,
        }
      }
    }

    throw new Error(
      `${C.ERROR_PREFIX}Failed to complete multipart upload: ${JSON.stringify(
        parsed,
      )}`,
    )
  }

  /** Aborts a multipart upload and removes all uploaded parts. */
  public override async abortMultipartUpload({
    key,
    uploadId,
    signal,
  }: IT.AbortMultipartUploadParams) {
    this._checkKey(key)
    if (!uploadId) {
      throw new TypeError(C.ERROR_UPLOAD_ID_REQUIRED)
    }

    const { xhr } = await this.request({

View on GitHub (pinned to 5d4dedd02a)