apache/hadoop · critical · IOException
Multipart upload incomplete: expected {} parts but got {}
Error message
Multipart upload incomplete: expected {} parts but got {} What it means
After close() waits for all part threads, it compares the collected eTags count against blkIndex - 1 (blocks uploaded). A mismatch means some thread finished without recording an ETag — a silent or lost failure with no uploadException — so completeMultipartUpload cannot be issued. The upload is aborted server-side and IOException 'Multipart upload incomplete: expected N parts but got M' is thrown; like error 37, no object is created.
Source
Thrown at hadoop-cloud-storage-project/hadoop-bos/src/main/java/org/apache/hadoop/fs/bos/BosOutputStream.java:417
e);
}
if (uploadException != null) {
abortMultipartUpload();
throw new IOException(
"Multipart upload failed", uploadException);
}
LOG.debug(
"success to wait upload part threads done");
LOG.debug(
"Size of eTags is {}. blkIndex is {}",
this.eTags.size(), this.blkIndex);
if (this.eTags.size() != this.blkIndex - 1) {
abortMultipartUpload();
throw new IOException(
"Multipart upload incomplete: expected "
+ (this.blkIndex - 1) + " parts but got "
+ this.eTags.size());
}
completeMultipartUpload(
bucketName, this.key,
this.uploadId, this.eTags);
}
super.close();
this.closed = true;
}
/**
* Aborts the in-progress multipart upload to prevent
* storage leakage on failure.
*/View on GitHub (pinned to 2add963021)
Solutions
- Scan the preceding logs for interrupted or failed upload threads — something silently dropped a part result
- Ensure close() runs on a healthy, non-interrupted thread; avoid killing tasks during their commit phase
- Retry the write from scratch; the abort guarantees no partial object remains
- Upgrade the connector if a known eTag-collection race is fixed in a newer hadoop-bos version
Defensive patterns
Strategy: retry
Type guard
static boolean isMultipartIncomplete(IOException e) {
return e.getMessage() != null && e.getMessage().startsWith("Multipart upload incomplete");
} Try / catch
catch (IOException e) {
if (isMultipartIncomplete(e)) {
// silent part loss: retry the whole write; ensure close() is not interrupted
rewriteFromSource(path);
} else { throw e; }
} Prevention
- Never kill/interrupt tasks during their commit (close) phase
- Call close() from a healthy thread; check Thread.interrupted() before commit
- Keep the connector version current to pick up upload-thread race fixes
When it happens
Trigger: An upload thread ends without propagating its exception or its ETag: task cancellation racing close(), JVM/thread-pool shutdown during commit, or a race in result collection after an earlier swallowed InterruptedException in the wait loop.
Common situations: Forcible task kill or speculation cancellation exactly at commit time; executor shutdown hooks closing streams on an interrupted thread; usually preceded by interrupt/timeout warnings in the logs.
Related errors
- Multipart upload failed
- Exception happens during upload:{}
- RequestRateLimitExceeded
- status code 429 !!!" + e.getCause()
- Invalid read parameters: buf.length=%d, off=%d, len=%d
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/b674758351b6b080.
Report an issue: GitHub.