transloadit/uppy · error · Error
${C.ERROR_PREFIX}CompleteMultipartUpload response missing Lo
Error message
${C.ERROR_PREFIX}CompleteMultipartUpload response missing Location or Key: ${JSON.stringify(r)} What it means
completeMultipartUpload parses S3's XML response; if the parsed result lacks Location and Key fields the client can't build a usable upload result, so it throws. This typically means the 200 response actually contained an error payload (S3 can return errors inside a 200 for this call).
Source
Thrown at packages/@uppy/aws-s3/src/s3-client/S3mini.ts:452
if (parsed && typeof parsed === 'object') {
// Check for both cases (camelCase from our parser, PascalCase from S3)
const result =
parsed.completeMultipartUploadResult ||
parsed.CompleteMultipartUploadResult ||
parsed
if (result && typeof result === 'object') {
const r = result as Record<string, unknown>
// S3 returns PascalCase (Location, Bucket, Key, ETag).
// Normalize to lowercase for our type interface.
const resultLocation = (r.Location || r.location) as string | undefined
const resultBucket = (r.Bucket || r.bucket) as string | undefined
const resultKey = (r.Key || r.key) as string | undefined
const rawEtag = (r.ETag || r.eTag || r.etag) as string | undefined
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,View on GitHub (pinned to 5d4dedd02a)
Solutions
- Retry completeMultipartUpload after a short delay (S3 eventual consistency on part listing)
- Log JSON.stringify(r) to see the actual payload; if it contains an Error code, address that (e.g. InvalidPart)
- Ensure all parts and ETags were sent correctly in the complete request
- Verify a standard S3-compatible endpoint is used and not mangling responses
Example fix
// before
await s3Mini.completeMultipartUpload({ key, uploadId, parts })
// after
try {
await s3Mini.completeMultipartUpload({ key, uploadId, parts })
} catch (err) {
if (String(err.message).includes('response missing Location or Key')) {
await delay(1000)
return s3Mini.completeMultipartUpload({ key, uploadId, parts })
}
throw err
} Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
null
Try / catch
try { await complete(...) } catch (e) { if (/response missing Location or Key/.test(String(e?.message))) { await delay(1000); return complete(...) } throw e } Prevention
- Retry completion once or twice with delay
- Verify all ETags sent match those returned by uploadPart
- Log the raw parsed response for diagnosis
When it happens
Trigger: Completing a multipart upload where S3 returns 200 with an <Error> body (e.g. InternalError or slow part propagation), or an unexpected/empty response body that fails XML parsing into the expected fields.
Common situations: Completing immediately after uploading the last part; transient S3 internal errors; custom endpoints/proxies that mangle the XML response.
Related errors
- S3 returned ${xhr.status}${serviceCode ? ` – ${serviceCode}`
- ERROR_UPLOAD_ID_REQUIRED
- ${C.ERROR_PREFIX}Failed to complete multipart upload: ${JSON
- ${C.ERROR_PREFIX}Failed to abort multipart upload: ${String(
- [s3mini] Failed to create multipart upload: ${JSON.stringify
AI-assisted analysis of transloadit/uppy@5d4dedd02a (2026-08-28).
Data as JSON: /api/errors/76aabeb60f00e80b.
Report an issue: GitHub.