{"record":{"id":"086bcaa66e94918b","repo":"apache/hadoop","slug":"client-is-not-the-lease-owner-inod","errorCode":null,"errorMessage":"Client (={}) is not the lease owner (={}: {} (inode {}) {}","messagePattern":"Client \\(=(.+?)\\) is not the lease owner \\(=(.+?): (.+?) \\(inode (.+?)\\) (.+?)","errorType":"exception","errorClass":"LeaseExpiredException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java","lineNumber":3274,"sourceCode":"    if (!inode.isFile()) {\n      throw new LeaseExpiredException(\"INode is not a regular file: \"\n          + leaseExceptionString(src, fileId, holder));\n    }\n    final INodeFile file = inode.asFile();\n    if (!file.isUnderConstruction()) {\n      throw new LeaseExpiredException(\"File is not open for writing: \"\n          + leaseExceptionString(src, fileId, holder));\n    }\n    // No further modification is allowed on a deleted file.\n    // A file is considered deleted, if it is not in the inodeMap or is marked\n    // as deleted in the snapshot feature.\n    if (isFileDeleted(file)) {\n      throw new FileNotFoundException(\"File is deleted: \"\n          + leaseExceptionString(src, fileId, holder));\n    }\n    final String owner = file.getFileUnderConstructionFeature().getClientName();\n    if (holder != null && !owner.equals(holder)) {\n      throw new LeaseExpiredException(\"Client (=\" + holder\n          + \") is not the lease owner (=\" + owner + \": \"\n          + leaseExceptionString(src, fileId, holder));\n    }\n    return file;\n  }\n \n  /**\n   * Complete in-progress write to the given file.\n   * @return true if successful, false if the client should continue to retry\n   *         (e.g if not all blocks have reached minimum replication yet)\n   * @throws IOException on error (eg lease mismatch, file not open, file deleted)\n   */\n  boolean completeFile(final String src, String holder,\n                       ExtendedBlock last, long fileId)\n    throws IOException {\n    boolean success = false;\n    final String operationName = \"completeFile\";\n    checkOperation(OperationCategory.WRITE);","sourceCodeStart":3256,"sourceCodeEnd":3292,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java#L3256-L3292","documentation":"Thrown as LeaseExpiredException when the holder string supplied by the client does not equal the client name stored in the file's FileUnderConstructionFeature. HDFS enforces single-writer semantics: only the lease owner may append, allocate blocks, or complete the file, so a mismatching client is rejected.","triggerScenarios":"Calling addBlock, completeFile, or updateBlock with a client name that differs from the creating writer; another client already ran recoverLease and took over the file; a zombie writer resumes after failover once its lease was reassigned.","commonSituations":"Two DFSOutputStreams opened on the same path (duplicate task attempts, a process that never died); append from a differently named client; a slow writer idle past the soft lease limit while another reader triggers recovery.","solutions":["Ensure exactly one writer per path: unique temp names per attempt, rename on commit","If the lease must change hands, call recoverLease(path), wait for it to succeed, then re-open the file with append()","Find and stop the zombie process still holding/renewing the old lease","For append workflows, open the file only after confirming lease ownership via getLeaseState/recovery, not by racing the current holder"],"exampleFix":"// before\nFSDataOutputStream out = dfs.append(path); // may hit LeaseExpiredException on close/addBlock\n\n// after\nif (!dfs.recoverLease(path)) { /* wait, then check isFileClosed */ }\nwhile (!dfs.isFileClosed(path)) { Thread.sleep(1000); }\nFSDataOutputStream out = dfs.append(path);","handlingStrategy":"retry","validationCode":"if (!dfs.isFileClosed(path)) {\n  boolean recovered = dfs.recoverLease(path);\n  // wait until isFileClosed before appending\n}","typeGuard":null,"tryCatchPattern":"try {\n  out.close();\n} catch (LeaseExpiredException e) {\n  // lease was taken over: recover, wait, then append to continue\n  recoverAndWaitThenAppend(path);\n}","preventionTips":["Guarantee one writer per path (unique client names, single task attempt)","Kill zombie writer processes before restarting jobs on the same output","For read access to open files, use recoverLease rather than racing the writer"],"tags":["hdfs","namenode","lease","single-writer","concurrency"],"backgroundTag":"lease-expired","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}