{"record":{"id":"d34cb55f4da961af","repo":"apache/hadoop","slug":"failed-to-truncate-file-src-for-clientname-on","errorCode":null,"errorMessage":"Failed to TRUNCATE_FILE <src> for <clientName> on <clientMachine> because <src> is being truncated.","messagePattern":"Failed to TRUNCATE_FILE <src> for <clientName> on <clientMachine> because <src> is being truncated\\.","errorType":"exception","errorClass":"AlreadyBeingCreatedException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirTruncateOp.java","lineNumber":117,"sourceCode":"\n      if (lpPolicy != null && lpPolicy.getId() == file.getStoragePolicyID()) {\n        throw new UnsupportedOperationException(\n            \"Cannot truncate lazy persist file \" + src);\n      }\n\n      // Check if the file is already being truncated with the same length\n      final BlockInfo last = file.getLastBlock();\n      if (last != null && last.getBlockUCState()\n          == BlockUCState.UNDER_RECOVERY) {\n        final BlockInfo truncatedBlock = last.getUnderConstructionFeature()\n            .getTruncateBlock();\n        if (truncatedBlock != null) {\n          final long truncateLength = file.computeFileSize(false, false)\n              + truncatedBlock.getNumBytes();\n          if (newLength == truncateLength) {\n            return new TruncateResult(false, fsd.getAuditFileInfo(iip));\n          } else {\n            throw new AlreadyBeingCreatedException(\n                RecoverLeaseOp.TRUNCATE_FILE.getExceptionMessage(src,\n                    clientName, clientMachine, src + \" is being truncated.\"));\n          }\n        }\n      }\n\n      // Opening an existing file for truncate. May need lease recovery.\n      fsn.recoverLeaseInternal(RecoverLeaseOp.TRUNCATE_FILE, iip, src,\n          clientName, clientMachine, false);\n      // Truncate length check.\n      long oldLength = file.computeFileSize();\n      if (oldLength == newLength) {\n        return new TruncateResult(true, fsd.getAuditFileInfo(iip));\n      }\n      if (oldLength < newLength) {\n        throw new HadoopIllegalArgumentException(\n            \"Cannot truncate to a larger file size. Current size: \" + oldLength\n                + \", truncate size: \" + newLength + \".\");","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirTruncateOp.java#L99-L135","documentation":"Thrown by the NameNode when a client calls truncate() on a file whose last block is already UNDER_RECOVERY from another in-flight truncate with a different target length. The NameNode detects the conflicting truncation and rejects it with AlreadyBeingCreatedException, protecting the file tail from two concurrent truncates producing inconsistent state. An idempotent retry with the same target length returns success instead of throwing.","triggerScenarios":"ClientProtocol.truncate(src, newLength) while another truncate or block/lease recovery holds the last block UNDER_RECOVERY with a truncateBlock whose implied target length differs from newLength. Same newLength takes the no-op success path; a different newLength throws.","commonSituations":"An application restarts and retries truncate with a recalculated length while the first truncate is still settling block recovery; two jobs compacting the same file concurrently; a truncate issued right after a writer crashed while recovery is running.","solutions":["Wait for the in-flight truncate/block recovery to finish (poll getFileStatus().getLen() until stable, or isFileClosed(path) true), then retry","Force a stuck lease with 'hdfs debug recoverLease -path <src>' or wait past the lease soft limit (dfs.namenode.lease-soft-limit-sec, default 60 s), then retry","Serialize truncates per file in application code (single owner or lock) so only one target length is ever in flight"],"exampleFix":"// before: two writers truncate concurrently with different lengths\nnew Thread(() -> dfs.truncate(path, 1_000L)).start();\nnew Thread(() -> dfs.truncate(path, 2_000L)).start(); // AlreadyBeingCreatedException\n\n// after: single owner; wait until the file is closed, then truncate\nDistributedFileSystem dfs = (DistributedFileSystem) fs;\nwhile (!dfs.isFileClosed(path)) {\n  Thread.sleep(1_000L);\n}\nboolean truncated = dfs.truncate(path, newLength);\nwhile (!truncated) { // false means block recovery in progress: re-invoke\n  Thread.sleep(1_000L);\n  truncated = dfs.truncate(path, newLength);\n}","handlingStrategy":"retry","validationCode":"DistributedFileSystem dfs = (DistributedFileSystem) fs;\n// only truncate when no writer or recovery holds the file\nif (dfs.isFileClosed(path)) {\n  boolean truncated = dfs.truncate(path, newLength);\n  // false => block recovery in progress, poll again\n}","typeGuard":null,"tryCatchPattern":"try {\n  dfs.truncate(path, newLength);\n} catch (AlreadyBeingCreatedException e) {\n  // another truncate/recovery owns the tail: back off, re-check, retry\n  Thread.sleep(2_000L);\n  if (dfs.isFileClosed(path)) {\n    dfs.truncate(path, newLength);\n  }\n}","preventionTips":["Route all truncates of a file through one owning process","Retry with the same newLength so the idempotent path can succeed","Check isFileClosed() before touching the tail of recently written files"],"tags":["hdfs","truncate","concurrency","lease-recovery","namenode"],"backgroundTag":"concurrent-write-conflict","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}