apache/hadoop · error · HadoopIllegalArgumentException

Cannot truncate to a negative file size: {}.

Error message

Cannot truncate to a negative file size: {}.

What it means

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.

Source

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

   * Truncation at block boundary is atomic, otherwise it requires
   * block recovery to truncate the last block of the file.
   *
   * @return true if client does not need to wait for block recovery,
   *         false if client needs to wait for block recovery.
   */
  boolean truncate(String src, long newLength, String clientName,
      String clientMachine, long mtime) throws IOException,
      UnresolvedLinkException {

    final String operationName = "truncate";
    requireEffectiveLayoutVersionForFeature(Feature.TRUNCATE);
    FSDirTruncateOp.TruncateResult r = null;
    FileStatus status;
    try {
      NameNode.stateChangeLog.info(
          "DIR* NameSystem.truncate: src={} newLength={}", src, newLength);
      if (newLength < 0) {
        throw new HadoopIllegalArgumentException(
            "Cannot truncate to a negative file size: " + newLength + ".");
      }
      checkOperation(OperationCategory.WRITE);
      final FSPermissionChecker pc = getPermissionChecker();
      FSPermissionChecker.setOperationType(operationName);
      writeLock(RwLockMode.GLOBAL);
      BlocksMapUpdateInfo toRemoveBlocks = new BlocksMapUpdateInfo();
      try {
        checkOperation(OperationCategory.WRITE);
        checkNameNodeSafeMode("Cannot truncate for " + src);
        r = FSDirTruncateOp.truncate(this, src, newLength, clientName,
            clientMachine, mtime, toRemoveBlocks, pc);
      } finally {
        status = r != null ? r.getFileStatus() : null;
        writeUnlock(RwLockMode.GLOBAL, operationName,
            getLockReportInfoSupplier(src, null, status));
      }
      getEditLog().logSync();

View on GitHub (pinned to 2add963021)

Solutions

  1. Clamp before calling: newLength = Math.max(0, Math.min(newLength, fileLen))
  2. Validate numeric input at the boundary and reject negative sizes with your own error message
  3. Treat -1/NaN from stat-like calls as errors, never as lengths

Example fix

// before
fs.truncate(path, requestedLen);
// after
long fileLen = fs.getFileStatus(path).getLen();
long target = Math.max(0L, Math.min(requestedLen, fileLen));
if (target != requestedLen) LOG.warn("clamped truncate target from {} to {}", requestedLen, target);
fs.truncate(path, target);
Defensive patterns

Strategy: validation

Validate before calling

if (newLength < 0) throw new IllegalArgumentException("newLength must be >= 0: " + newLength);
long fileLen = fs.getFileStatus(path).getLen();
if (newLength > fileLen) throw new IllegalArgumentException("newLength " + newLength + " > file size " + fileLen);

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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