apache/hadoop · error · RuntimeException
part num mismatched: %d != %d
Error message
part num mismatched: %d != %d
What it means
FileStore.completeUpload() sorts the staged part-file numbers and the caller's uploadParts by part number, then walks them pairwise; if part.num() differs from the i-th staged part number it throws 'part num mismatched'. The set of part numbers on disk and the set in the request are not identical (gap, duplicate, or shifted numbering), even though the counts matched.
Source
Thrown at hadoop-cloud-storage-project/hadoop-tos/src/main/java/org/apache/hadoop/fs/tosfs/object/FileStore.java:429
List<Integer> partNums = listPartNums(uploadDir);
if (partNums.size() != uploadParts.size()) {
throw new RuntimeException(String.format("parts length mismatched: %d != %d",
partNums.size(), uploadParts.size()));
}
Collections.sort(partNums);
uploadParts.sort(Comparator.comparingInt(Part::num));
Path keyPath = path(encode(key));
File tmpFile = createTmpFile(keyPath.toFile());
try (FileOutputStream outputStream = new FileOutputStream(tmpFile);
FileChannel outputChannel = outputStream.getChannel()) {
int offset = 0;
for (int i = 0; i < partNums.size(); i++) {
Part part = uploadParts.get(i);
if (part.num() != partNums.get(i)) {
throw new RuntimeException(
String.format("part num mismatched: %d != %d", part.num(), partNums.get(i)));
}
File partFile = new File(uploadDir, String.valueOf(part.num()));
checkPartFile(part, partFile);
try (FileInputStream inputStream = new FileInputStream(partFile);
FileChannel inputChannel = inputStream.getChannel()) {
outputChannel.transferFrom(inputChannel, offset, partFile.length());
offset += partFile.length();
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
if (!tmpFile.renameTo(keyPath.toFile())) {
throw new RuntimeException("rename file failed");View on GitHub (pinned to 2add963021)
Solutions
- Assign each part number exactly once at upload time and never renumber: numbers on disk must equal the sorted numbers in your parts list
- Feed completeUpload the untouched List<Part> returned by the upload calls
- If any part failed or numbering diverged, abort the upload and redo all parts under a new uploadId with fresh 1..N numbering
- Never write files into __STAGING__/<key>/<uploadId> yourself — file names are the part numbers
Example fix
// before: renumbered parts between upload and complete List<Part> shifted = parts.stream().map(p -> new Part(p.num() - 1, p.size(), p.eTag())).collect(toList()); storage.completeUpload(key, uploadId, shifted); // part num mismatched: 0 != 1 // after: pass the parts exactly as returned by uploadPart storage.completeUpload(key, uploadId, partsFromUploadCalls);
Defensive patterns
Strategy: validation
Validate before calling
List<Integer> nums = parts.stream().map(Part::num).sorted()
.collect(java.util.stream.Collectors.toList());
for (int i = 0; i < nums.size(); i++) {
if (nums.get(i) != i + 1) {
throw new IOException("part numbers must be exactly 1..N; got " + nums);
}
}
storage.completeUpload(key, uploadId, parts); Prevention
- Assign part numbers once at upload time and never renumber between upload and complete
- Feed the untouched List<Part> from the upload calls straight into completeUpload
- When mixing uploadPart and uploadPartCopy, allocate part numbers from one counter to avoid clashes
- Remember staging file names ARE the part numbers: never rename or add files there
When it happens
Trigger: completeUpload where part numbers were re-assigned between upload and complete (e.g. re-uploading with different numbering), a part file was renamed/removed and a later part renumbered to fill the gap, or the caller reorders/renumbers its Part list (uploadPartCopy results spliced into an uploadPart sequence with clashing numbers).
Common situations: Mixing uploadPart and uploadPartCopy results with independently chosen part numbers; recovery code that re-numbers parts; tests that stage part files manually with names like 0, 1, 2 (listPartNums reads the file names as the numbers, and part numbers must be a strictly matching sorted sequence).
Related errors
- parts length mismatched: %d != %d
- part size mismatched: %d != %d
- part etag mismatched: %s != %s
- Failed to create MultipartUpload with key: %s
- cannot locate the upload id: %s
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/97e73e9c8c6f18be.
Report an issue: GitHub.