apache/hadoop · error · IOException

The blockCollection of {} is null, likely because the file o

Error message

The blockCollection of {} is null, likely because the file owning this block was deleted and the block removal is delayed

What it means

storedBlock.isDeleted() is true: the block's blockCollection was nulled because the owning file was deleted and physical block removal is delayed for performance. commitBlockSynchronization throws IOException here instead of hitting an NPE, and avoids appending a CloseOp edit for a dead file (HDFS-6825).

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java:4106

          throw new IOException("Block (=" + oldBlock + ") not found");
        }
      }
      final long oldGenerationStamp = storedBlock.getGenerationStamp();
      final long oldNumBytes = storedBlock.getNumBytes();
      //
      // The implementation of delete operation (see @deleteInternal method)
      // first removes the file paths from namespace, and delays the removal
      // of blocks to later time for better performance. When
      // commitBlockSynchronization (this method) is called in between, the
      // blockCollection of storedBlock could have been assigned to null by
      // the delete operation, throw IOException here instead of NPE; if the
      // file path is already removed from namespace by the delete operation,
      // throw FileNotFoundException here, so not to proceed to the end of
      // this method to add a CloseOp to the edit log for an already deleted
      // file (See HDFS-6825).
      //
      if (storedBlock.isDeleted()) {
        throw new IOException("The blockCollection of " + storedBlock
            + " is null, likely because the file owning this block was"
            + " deleted and the block removal is delayed");
      }
      final INodeFile iFile = getBlockCollection(storedBlock);
      src = iFile.getFullPathName();
      if (isFileDeleted(iFile)) {
        throw new FileNotFoundException("File not found: "
            + src + ", likely due to delayed block removal");
      }
      if ((!iFile.isUnderConstruction() || storedBlock.isComplete()) &&
          iFile.getLastBlock().isComplete()) {
        if (LOG.isDebugEnabled()) {
          LOG.debug("Unexpected block (={}) since the file (={}) is not under construction",
              oldBlock, iFile.getLocalName());
        }

        return;
      }

View on GitHub (pinned to 2add963021)

Solutions

  1. Treat the write as terminally failed: the file is gone, so no commit is needed
  2. If the file should still exist, verify with getFileStatus and re-run the client operation once block GC has settled
  3. Serialize application-level delete and finalize so they cannot interleave on the same path
Defensive patterns

Strategy: try-catch

Try / catch

try {
  commitBlockSynchronization(oldBlock, newGs, newLen, ...);
} catch (IOException e) {
  if (e.getMessage().contains("blockCollection") && !fs.exists(path)) {
    return; // file deleted, delayed block removal: no-op
  }
  throw e;
}

Prevention

When it happens

Trigger: A delete removes the path from the namespace first and invalidates blocks later; commitBlockSynchronization arrives inside that window and finds a block whose owner is already detached.

Common situations: Users deleting output files at the exact moment a failed write is being recovered; cleanup jobs racing stragglers; committer aborting a task while its pipeline syncs.

Related errors


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