apache/hadoop · error · IOException

Failed to move {path} to trash {trashPath}

Error message

Failed to move {path} to trash {trashPath}

What it means

Thrown by TrashPolicyDefault.moveToTrash after two failed attempts to move the path into the trash (mkdirs + rename into .Trash/Current, with a timestamp suffix retry inside the loop). The original cause - the IOException from the last fs.rename - is attached, so the message tells you what was being moved where, and getCause() tells you why.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/TrashPolicyDefault.java:202

      try {
        // if the target path in Trash already exists, then append with 
        // a current time in millisecs.
        String orig = trashPath.toString();
        
        while(fs.exists(trashPath)) {
          trashPath = new Path(orig + Time.now());
        }
        
        // move to current trash
        fs.rename(path, trashPath,
            Rename.TO_TRASH);
        LOG.info("Moved: '" + path + "' to trash at: " + trashPath);
        return true;
      } catch (IOException e) {
        cause = e;
      }
    }
    throw new IOException("Failed to move " + path + " to trash " + trashPath,
        cause);
  }

  @SuppressWarnings("deprecation")
  @Override
  public void createCheckpoint() throws IOException {
    createCheckpoint(new Date());
  }

  @SuppressWarnings("deprecation")
  public void createCheckpoint(Date date) throws IOException {
    Collection<FileStatus> trashRoots = fs.getTrashRoots(false);
    for (FileStatus trashRoot: trashRoots) {
      LOG.info("TrashPolicyDefault#createCheckpoint for trashRoot: " +
          trashRoot.getPath());
      createCheckpoint(trashRoot.getPath(), date);
    }
  }

View on GitHub (pinned to 2add963021)

Solutions

  1. Inspect the attached cause: AccessControlException -> fix .Trash ownership/permissions; QuotaExceededException -> raise quota or expunge; IOException disk full -> free space
  2. Run 'hadoop fs -expunge' (or empty .Trash) to make room, then retry the delete
  3. If the data must go now and trash is the blocker: re-run with -skipTrash after confirming permanent deletion is acceptable
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight the trash destination before deleting
Path trashRoot = fs.getTrashRoot(path);
if (!fs.exists(trashRoot)) {
  fs.mkdirs(trashRoot, new FsPermission((short)0700));
}
// let quota/permission failures surface now with a clear context
fs.getFileStatus(trashRoot);

Try / catch

try {
  fs.delete(path, true);
} catch (IOException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("Failed to move")) {
    Throwable c = e.getCause(); // real reason: perms, quota, disk full
    // fix per cause, expunge trash, then retry once
  }
}

Prevention

When it happens

Trigger: Trash directory not creatable (permissions on user home), quota exceeded at the trash destination, disk full on the volume holding .Trash, or a pre-existing target that could not be renamed over. The two-iteration loop exists to survive a concurrent checkpoint renaming Current underneath it; anything failing both times is fatal.

Common situations: User home quota exhausted before a big cleanup; trash root owned by another user after UID changes; shared clusters where .Trash perms were tightened; deleting during a concurrent expunge.

Related errors


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