{"record":{"id":"b618518d361db531","repo":"apache/hadoop","slug":"attempted-to-write-to-file-without-lease","errorCode":null,"errorMessage":"Attempted to write to file without lease","messagePattern":"Attempted to write to file without lease","errorType":"exception","errorClass":"PathIOException","httpStatus":null,"severity":"critical","filePath":"hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsOutputStream.java","lineNumber":461,"sourceCode":"   * @throws IOException if an I/O error occurs. In particular, an IOException may be\n   *                     thrown if the output stream has been closed.\n   */\n  @Override\n  public synchronized void write(final byte[] data, final int off, final int length)\n      throws IOException {\n    if (closed) {\n      throw new IOException(FSExceptionMessages.STREAM_IS_CLOSED);\n    }\n    // validate if data is not null and index out of bounds.\n    DataBlocks.validateWriteArgs(data, off, length);\n    maybeThrowLastError();\n\n    if (off < 0 || length < 0 || length > data.length - off) {\n      throw new IndexOutOfBoundsException();\n    }\n\n    if (hasLease() && isLeaseFreed()) {\n      throw new PathIOException(path, ERR_WRITE_WITHOUT_LEASE);\n    }\n    if (length == 0) {\n      LOG.debug(\"No data to write, length is 0 for path: {}\", path);\n      return;\n    }\n\n    AbfsBlock block = createBlockIfNeeded(position);\n    int written = bufferData(block, data, off, length);\n    // Update the incremental MD5 hash with the written data.\n    if (isChecksumValidationEnabled()) {\n      getMessageDigest().update(data, off, written);\n    }\n    // Update the full blob MD5 hash with the written data.\n    if (isFullBlobChecksumValidationEnabled()) {\n      getFullBlobContentMd5().update(data, off, written);\n    }\n    int remainingCapacity = block.remainingCapacity();\n","sourceCodeStart":443,"sourceCodeEnd":479,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsOutputStream.java#L443-L479","documentation":"AbfsOutputStream.write throws PathIOException with ERR_WRITE_WITHOUT_LEASE (\"Attempted to write to file without lease...\") when the stream holds a lease (hasLease()) but that lease has already been freed (isLeaseFreed()). The lease enforces single-writer semantics; once freed — typically because the lease was lost, expired, or released after a failure — further writes are rejected rather than silently writing unguarded.","triggerScenarios":"The lease expired because renewals (LeaseTimerTask) fell behind — fixed-duration lease too short, GC pauses, thread starvation, or network problems; the lease was broken/acquired by another client (e.g., someone ran a break-lease tool or a competing writer); a prior REST failure freed the lease and the application kept writing.","commonSituations":"Long-running output streams with fs.azure.lease features enabled; operators breaking 'stuck' leases while a job is still writing; competing jobs/tools writing the same path; async lease tasks failing due to the lease thread pool being saturated.","solutions":["Fail the write task and restart it on a fresh stream — writing without the lease would risk lost updates","If you must continue, acquire a new lease (free/reacquire or reopen the output stream)","Review lease settings (duration/renewal) and ensure the lease thread pool is healthy (fs.azure.lease.threads)","Eliminate competing writers/break-lease operations on the same path"],"exampleFix":"// before\nout.write(buf, 0, len);   // PathIOException: write without lease\n\n// after\ntry {\n  out.write(buf, 0, len);\n} catch (PathIOException e) {\n  if (e.getMessage().contains(\"without lease\")) {\n    // lease lost: stop, then restart the writer on a fresh stream/lease\n    throw new IOException(\"Lease lost for \" + path\n        + \"; restart this write task\", e);\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Nothing to validate locally — lease loss is server-side.\n// Mitigate: flush frequently so a lease loss loses little data\nout.hflush();   // keep unflushed window small while leasing","typeGuard":null,"tryCatchPattern":"try {\n  out.write(buf, 0, len);\n} catch (PathIOException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"without lease\")) {\n    // single-writer guarantee broken: fail the task / reopen with a new lease\n    throw new IOException(\"ABFS lease lost for \" + path + \"; restart writer\", e);\n  }\n  throw e;\n}","preventionTips":["Ensure exactly one writer per path; no ad-hoc break-lease operations during jobs","Keep lease durations/renewal healthy and the lease thread pool sized (fs.azure.lease.threads)","Design writers to be restartable: idempotent output paths so a lease loss is recoverable"],"tags":["azure-blob","abfs","lease","concurrency","single-writer","hadoop"],"backgroundTag":"lease-lost","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}