{"record":{"id":"878fef3d7f4550b0","repo":"apache/hadoop","slug":"cannot-truncate-to-a-negative-file-size","errorCode":null,"errorMessage":"Cannot truncate to a negative file size: {}.","messagePattern":"Cannot truncate to a negative file size: (.+?)\\.","errorType":"validation","errorClass":"HadoopIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java","lineNumber":2421,"sourceCode":"   * Truncation at block boundary is atomic, otherwise it requires\n   * block recovery to truncate the last block of the file.\n   *\n   * @return true if client does not need to wait for block recovery,\n   *         false if client needs to wait for block recovery.\n   */\n  boolean truncate(String src, long newLength, String clientName,\n      String clientMachine, long mtime) throws IOException,\n      UnresolvedLinkException {\n\n    final String operationName = \"truncate\";\n    requireEffectiveLayoutVersionForFeature(Feature.TRUNCATE);\n    FSDirTruncateOp.TruncateResult r = null;\n    FileStatus status;\n    try {\n      NameNode.stateChangeLog.info(\n          \"DIR* NameSystem.truncate: src={} newLength={}\", src, newLength);\n      if (newLength < 0) {\n        throw new HadoopIllegalArgumentException(\n            \"Cannot truncate to a negative file size: \" + newLength + \".\");\n      }\n      checkOperation(OperationCategory.WRITE);\n      final FSPermissionChecker pc = getPermissionChecker();\n      FSPermissionChecker.setOperationType(operationName);\n      writeLock(RwLockMode.GLOBAL);\n      BlocksMapUpdateInfo toRemoveBlocks = new BlocksMapUpdateInfo();\n      try {\n        checkOperation(OperationCategory.WRITE);\n        checkNameNodeSafeMode(\"Cannot truncate for \" + src);\n        r = FSDirTruncateOp.truncate(this, src, newLength, clientName,\n            clientMachine, mtime, toRemoveBlocks, pc);\n      } finally {\n        status = r != null ? r.getFileStatus() : null;\n        writeUnlock(RwLockMode.GLOBAL, operationName,\n            getLockReportInfoSupplier(src, null, status));\n      }\n      getEditLog().logSync();","sourceCodeStart":2403,"sourceCodeEnd":2439,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSNamesystem.java#L2403-L2439","documentation":"FSNamesystem.truncate validates newLength before taking locks or logging edits: a negative target size is meaningless for a file and is rejected immediately with HadoopIllegalArgumentException.","triggerScenarios":"ClientProtocol.truncate / DistributedFileSystem.truncate(path, newLength) invoked with newLength < 0 — usually unchecked arithmetic such as newLen = currentLen - delta where delta > currentLen, a -1 sentinel from a failed stat call, or raw user input forwarded unvalidated.","commonSituations":"Apps computing truncation offsets from sizes fetched from another system whose API returned -1 on error; CLI tools forwarding raw numeric arguments; unit tests with edge-case sizes hitting a real cluster.","solutions":["Clamp before calling: newLength = Math.max(0, Math.min(newLength, fileLen))","Validate numeric input at the boundary and reject negative sizes with your own error message","Treat -1/NaN from stat-like calls as errors, never as lengths"],"exampleFix":"// before\nfs.truncate(path, requestedLen);\n// after\nlong fileLen = fs.getFileStatus(path).getLen();\nlong target = Math.max(0L, Math.min(requestedLen, fileLen));\nif (target != requestedLen) LOG.warn(\"clamped truncate target from {} to {}\", requestedLen, target);\nfs.truncate(path, target);","handlingStrategy":"validation","validationCode":"if (newLength < 0) throw new IllegalArgumentException(\"newLength must be >= 0: \" + newLength);\nlong fileLen = fs.getFileStatus(path).getLen();\nif (newLength > fileLen) throw new IllegalArgumentException(\"newLength \" + newLength + \" > file size \" + fileLen);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never forward raw user input as byte lengths","Treat -1 from stat-style calls as an error, never a size"],"tags":["hdfs","truncate","argument-validation","hdfs-file-api"],"backgroundTag":"negative-argument-validation","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}