apache/hadoop · error · LeaseExpiredException

File is not open for writing: {} (inode {}) {}

Error message

File is not open for writing: {} (inode {}) {}

What it means

checkLease's regular-file case: the file exists but is no longer under construction — it was closed (by close, lease recovery, or another writer) while this client still believed it held the lease. The next addBlock/close on that src fails with LeaseExpiredException('File is not open for writing').

Source

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

        : "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 + ": "
          + leaseExceptionString(src, fileId, holder));
    }
    return file;
  }
 

View on GitHub (pinned to 2add963021)

Solutions

  1. Reopen with append() (or re-create) and continue from the last flushed length — the old handle is dead
  2. Fix the root cause: close streams in finally, keep the lease renewer thread healthy, avoid JVM pauses near the lease limits
  3. If another writer legitimately took over, switch to single-writer coordination instead of fighting the lease

Example fix

// before: stale handle from before the lease was reclaimed
out.write(buf, 0, n); out.close();   // LeaseExpiredException
// after
long len = fs.getFileStatus(path).getLen();
try (FSDataOutputStream out = ((DistributedFileSystem) fs).append(path)) {
  /* re-append everything beyond len */
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!((DistributedFileSystem) fs).isFileClosed(path)) {
  // still open (by us or someone else); if not by us, expect lease contention
}

Try / catch

catch (LeaseExpiredException e) { if (e.getMessage() != null && e.getMessage().contains("not open for writing")) { long len = fs.getFileStatus(src).getLen(); reopenAppendAndContinueFrom(len); } else throw e; }

Prevention

When it happens

Trigger: A client's write handle outlives its lease: another client/admin ran recoverLease, hard-limit expiry closed the file, or the file was closed and the same handle kept being used; the next block allocation then fails.

Common situations: Long GC pauses or a stalled DFSClient lease-renewer thread so the NN reclaims and closes the lease; automation ran recoverLease on live files; retry logic writing to an already-closed file.

Related errors


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