{"record":{"id":"b62ad375922395c4","repo":"apache/hadoop","slug":"input-output-error","errorCode":null,"errorMessage":"Input/output error","messagePattern":"Input/output error","errorType":"exception","errorClass":"PathIOException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/Delete.java","lineNumber":124,"sourceCode":"    protected void processNonexistentPath(PathData item) throws IOException {\n      if (!ignoreFNF) super.processNonexistentPath(item);\n    }\n\n    @Override\n    protected void processPath(PathData item) throws IOException {\n      if (item.stat.isDirectory() && !deleteDirs) {\n        throw new PathIsDirectoryException(item.toString());\n      }\n\n      // TODO: if the user wants the trash to be used but there is any\n      // problem (ie. creating the trash dir, moving the item to be deleted,\n      // etc), then the path will just be deleted because moveToTrash returns\n      // false and it falls thru to fs.delete.  this doesn't seem right\n      if (moveToTrash(item) || !canBeSafelyDeleted(item)) {\n        return;\n      }\n      if (!item.fs.delete(item.path, deleteDirs)) {\n        throw new PathIOException(item.toString());\n      }\n      out.println(\"Deleted \" + item);\n    }\n\n    private boolean canBeSafelyDeleted(PathData item)\n        throws IOException {\n      boolean shouldDelete = true;\n      if (safeDelete) {\n        final long deleteLimit = getConf().getLong(\n            HADOOP_SHELL_SAFELY_DELETE_LIMIT_NUM_FILES,\n            HADOOP_SHELL_SAFELY_DELETE_LIMIT_NUM_FILES_DEFAULT);\n        if (deleteLimit > 0) {\n          ContentSummary cs = item.fs.getContentSummary(item.path);\n          final long numFiles = cs.getFileCount();\n          if (numFiles > deleteLimit) {\n            if (!ToolRunner.confirmPrompt(\"Proceed deleting \" + numFiles +\n                \" files?\")) {\n              System.err.println(\"Delete aborted at user request.\\n\");","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/Delete.java#L106-L142","documentation":"PathIOException with the POSIX EIO text 'Input/output error' (PathIOException.java default message, rendered as `path`: Input/output error) thrown by Rm.processPath (Delete.java:124) when FileSystem.delete(path, recursive) returns false instead of throwing — the filesystem acknowledged the call but did not remove the path. This is a catch-all for delete failures the FS implementation signals via boolean rather than an exception.","triggerScenarios":"fs.delete returning false: missing write permission on the file or its parent directory (HDFS permissions), the path being re-created by a concurrent writer between check and delete, viewfs/mount-table oddities, or a filesystem driver bug. Note this line is only reached after moveToTrash and the safe-delete gauge pass, so trash is not the culprit here.","commonSituations":"Cleanup jobs running as a user without write rights on the parent HDFS directory; racing MapReduce/Spark tasks that recreate output files; intermittent cluster issues where the NameNode answers listStatus but delete fails.","solutions":["Verify permissions: 'hdfs dfs -ls /parent' and check the owner/group bits; fix with hdfs dfs -chmod/-chown as needed","Check whether the path still exists after the failure ('hdfs dfs -ls path') — if it is gone, the delete raced and nothing is wrong","Retry once after permissions are fixed; inspect NameNode logs if it persists","If a concurrent job recreates the path, coordinate deletion (stop the writer first) instead of retrying"],"exampleFix":"// before\nif (!fs.delete(path, false)) { /* ignored */ }\n\n// after\ntry {\n  if (!fs.delete(path, false)) {\n    throw new PathIOException(path.toString());\n  }\n} catch (PathIOException e) {\n  LOG.warn(\"delete failed for {}: {}\", path, e.getMessage());\n  // re-check existence + permissions, then retry once\n}","handlingStrategy":"retry","validationCode":"if (fs.exists(path)) {\n  FileStatus parent = fs.getFileStatus(path.getParent());\n  // require write access on parent before attempting delete\n}","typeGuard":null,"tryCatchPattern":"try {\n  if (!fs.delete(path, recursive)) {\n    throw new PathIOException(path.toString());\n  }\n} catch (PathIOException e) {\n  if (!fs.exists(path)) return;      // raced: already gone\n  // verify/repair parent permissions, then retry once\n  if (!fs.delete(path, recursive)) throw e;\n}","preventionTips":["Check write permission on the parent directory before deletes","Treat delete()==false as a real failure, never ignore the boolean","Re-check existence after a failed delete to detect benign races"],"tags":["hadoop","delete","rm","io-error","permissions","shell"],"backgroundTag":"file-delete-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}