apache/hadoop · error · IOException

Failed to delete {pTask}

Error message

Failed to delete {pTask}

What it means

During cleanUpPartialOutputForTask, the committer loops over earlier task-attempt directories (attempt 0..N-1 under the committed task path) and deletes each one. If FileSystem.delete(path, recursive=true) returns false AND the path still exists afterwards, it throws IOException('Failed to delete <path>') because a stale committed attempt could otherwise be double-committed later. This indicates the filesystem refused or partially performed the delete.

Source

Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/lib/output/PartialFileOutputCommitter.java:101

      throw new IllegalStateException("Invoking cleanUpPartialOutputForTask() " +
          "from non @Preemptable class");
    }
    FileSystem fs =
      fsFor(getTaskAttemptPath(context), context.getConfiguration());

    LOG.info("cleanUpPartialOutputForTask: removing everything belonging to " +
        context.getTaskAttemptID().getTaskID() + " in: " +
        getCommittedTaskPath(context).getParent());

    final TaskAttemptID taid = context.getTaskAttemptID();
    final TaskID tid = taid.getTaskID();
    Path pCommit = getCommittedTaskPath(context).getParent();
    // remove any committed output
    for (int i = 0; i < taid.getId(); ++i) {
      TaskAttemptID oldId = new TaskAttemptID(tid, i);
      Path pTask = new Path(pCommit, oldId.toString());
      if (!fs.delete(pTask, true) && fs.exists(pTask)) {
        throw new IOException("Failed to delete " + pTask);
      }
    }
  }

}

View on GitHub (pinned to 2add963021)

Solutions

  1. Check permissions and ownership of the committed-task parent directory (the directory printed via getCommittedTaskPath(context).getParent()) and fix with chown/chmod.
  2. Verify the filesystem is healthy (out of safemode, no failover in progress) and retry the preemption cleanup.
  3. Look for a concurrent process deleting the same paths; if one exists, remove the race or accept that delete can return false because the path is already gone.
  4. As a last resort, manually remove the stale attempt directory named in the message and rerun.
Defensive patterns

Strategy: retry

Validate before calling

// before cleanup: prove the output tree is deletable by this user
Path parent = FileOutputCommitter.getCommittedTaskPath(context).getParent();
FileSystem fs = parent.getFileSystem(conf);
if (!fs.getFileStatus(parent).getPermission()
        .getUserAction().implies(FsAction.WRITE)) {
  throw new IOException("No write permission on " + parent + " - fix before cleanup");
}

Try / catch

try {
  committer.cleanUpPartialOutputForTask(context);
} catch (IOException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("Failed to delete")) {
    // transient FS state: verify health, fix permissions, then retry once
  }
}

Prevention

When it happens

Trigger: fs.delete(pTask, true) returning false while fs.exists(pTask) is true, for a previously committed attempt directory: no write/parent permission on the output tree, HDFS in safemode, a concurrent cleaner racing the delete, or a store returning inconsistent results.

Common situations: Output directory owned by a different user than the one running cleanup (e.g. yarn vs. submitter after a manual mkdir); HDFS safemode or namemode failover mid-operation; external scripts pruning the same directories; NFS/mount flakiness on the staging area.

Related errors


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