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

  1. Assign each part number exactly once at upload time and never renumber: numbers on disk must equal the sorted numbers in your parts list
  2. Feed completeUpload the untouched List<Part> returned by the upload calls
  3. If any part failed or numbering diverged, abort the upload and redo all parts under a new uploadId with fresh 1..N numbering
  4. 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

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


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/97e73e9c8c6f18be. Report an issue: GitHub.