apache/hadoop · error · LeaseExpiredException
INode is not a regular file: {} (inode {}) {}
Error message
INode is not a regular file: {} (inode {}) {} What it means
checkLease found that the resolved last INode is not a regular file (a directory or symlink). A write lease only applies to files, so the caller gets LeaseExpiredException('INode is not a regular file: ...') with path, inode id, and holder context.
Source
Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java:3257
}
private String leaseExceptionString(String src, long fileId, String holder) {
final Lease lease = leaseManager.getLease(holder);
return src + " (inode " + fileId + ") " + (lease != null? lease.toString()
: "Holder " + holder + " does not have any open files.");
}
INodeFile checkLease(INodesInPath iip, String holder, long fileId)
throws LeaseExpiredException, FileNotFoundException {
String src = iip.getPath();
INode inode = iip.getLastINode();
assert hasReadLock(RwLockMode.FS);
if (inode == null) {
throw new FileNotFoundException("File does not exist: "
+ leaseExceptionString(src, fileId, holder));
}
if (!inode.isFile()) {
throw new LeaseExpiredException("INode is not a regular file: "
+ leaseExceptionString(src, fileId, holder));
}
final INodeFile file = inode.asFile();
if (!file.isUnderConstruction()) {
throw new LeaseExpiredException("File is not open for writing: "
+ leaseExceptionString(src, fileId, holder));
}
// No further modification is allowed on a deleted file.
// A file is considered deleted, if it is not in the inodeMap or is marked
// as deleted in the snapshot feature.
if (isFileDeleted(file)) {
throw new FileNotFoundException("File is deleted: "
+ leaseExceptionString(src, fileId, holder));
}
final String owner = file.getFileUnderConstructionFeature().getClientName();
if (holder != null && !owner.equals(holder)) {
throw new LeaseExpiredException("Client (=" + holder
+ ") is not the lease owner (=" + owner + ": "View on GitHub (pinned to 2add963021)
Solutions
- Write to a file path under the directory (parent + filename), never the directory itself
- If the path was hijacked, pick a new output path and restart the write
- Type-check the target with getFileStatus().isFile() before starting long writes
Example fix
// before FSDataOutputStream out = fs.create(dirPath); // dirPath is a directory -> LeaseExpiredException // after FSDataOutputStream out = fs.create(new Path(dirPath, "part-0000"));
Defensive patterns
Strategy: validation
Validate before calling
FileStatus st = fs.getFileStatus(p);
if (!st.isFile()) throw new IllegalArgumentException("not a regular file: " + p); Type guard
static boolean isRegularFile(FileSystem fs, Path p) throws IOException {
try { return fs.getFileStatus(p).isFile(); }
catch (FileNotFoundException e) { return false; }
} Try / catch
catch (LeaseExpiredException e) { if (e.getMessage() != null && e.getMessage().contains("not a regular file")) failWithBadPathHint(); else throw e; } Prevention
- Derive file paths explicitly as parent directory + filename
- Type-check paths that come from config or user input before long writes
When it happens
Trigger: addBlock/close/append-family calls with a src that resolves to a directory — the writer's file was deleted and the path re-created as a directory, or the path string always was a directory path used as a file target.
Common situations: Path template bugs that append a filename to a path which itself names a directory; another job replaced the file with a same-named directory; snapshot restore changed the inode type under an active writer.
Related errors
- Data node {nodeID} is attempting to report storage ID {datan
- "concat: target file " + target + " is under construction"
- <src> for client <clientMachine> already exists
- Failed to {} {} for {} on {} because {} is already the curre
- Failed to {} {} for {} on {} because the file is under const
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/1cab950e250dd1c8.
Report an issue: GitHub.