apache/hadoop · error · FileNotFoundException
File not found: {}, likely due to delayed block removal
Error message
File not found: {}, likely due to delayed block removal What it means
In commitBlockSynchronization, the block's inode resolves but isFileDeleted reports the file's path was removed (or snapshot-deleted) while its blocks await delayed removal. FileNotFoundException is thrown so no CloseOp edit is logged for an already-deleted file (HDFS-6825 family).
Source
Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java:4113
// 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;
}
truncatedBlock = iFile.getLastBlock();
final long recoveryId = truncatedBlock.getUnderConstructionFeature()
.getBlockRecoveryId();
copyTruncate = truncatedBlock.getBlockId() != storedBlock.getBlockId();
if(recoveryId != newgenerationstamp) {
throw new IOException("The recovery id " + newgenerationstampView on GitHub (pinned to 2add963021)
Solutions
- Confirm with getFileStatus whether the path is really gone; if yes, abandon the write
- Retry the client operation only after confirming the file survives and the delete storm is over
- Move deletes and finalize/close into the same serialized section of the application
Defensive patterns
Strategy: validation
Validate before calling
for (String p : srcs) {
if (!fs.exists(new Path(p))) { /* skip or fail early with clear cause */ }
} Try / catch
try {
commitBlockSynchronization(oldBlock, newGs, newLen, ...);
} catch (FileNotFoundException e) {
if (e.getMessage().contains("delayed block removal")) { return; }
throw e;
} Prevention
- Re-check getFileStatus when commit-time failures mention delayed removal
- Coordinate deletes with writer lifecycle to avoid the race window
When it happens
Trigger: Same delete-vs-commit race as the sibling checks, but reached one step later: the block still has its inode attached while the path is already gone.
Common situations: File deleted concurrently with block-synchronization retries; snapshot deletions pinning the inode after the path is removed.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Directory does not exist: {}
- File does not exist: {}
- Recovery block {b} where it is not under construction.
- "File/Directory " + iip.getPath() + " does not exist."
- File is deleted: {} (inode {}) {}
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/b1e8ee9e3f5c4cb8.
Report an issue: GitHub.