{"record":{"id":"9471f95e8f5d5437","repo":"apache/hadoop","slug":"directory-is-not-empty","errorCode":null,"errorMessage":"Directory {} is not empty.","messagePattern":"Directory (.+?) is not empty\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-cloud-storage-project/hadoop-bos/src/main/java/org/apache/hadoop/fs/bos/HierarchyBosNativeFileSystemStore.java","lineNumber":115,"sourceCode":"  protected boolean isHierarchy() {\n    return true;\n  }\n\n  /**\n   * {@inheritDoc}\n   *\n   * Deletes a directory. For non-recursive deletes, verifies\n   * the directory is empty first.\n   */\n  @Override\n  public void deleteDirs(\n      String key, boolean recursive) throws IOException {\n    if (!recursive) {\n      PartialListing listing =\n          list(key, 1, null, \"/\");\n      if (listing.getFiles().length\n          + listing.getDirectories().length > 0) {\n        throw new IOException(\n            \"Directory \" + key + \" is not empty.\");\n      }\n      delete(key);\n    } else {\n      String marker = null;\n      DeleteDirectoryResponse response = null;\n      do {\n        response = bosClientProxy.deleteDirectory(\n            bucketName, key, true, marker);\n        if (response != null\n            && response.isTruncated()) {\n          marker = response.getNextDeleteMarker();\n        } else {\n          break;\n        }\n      } while (response.isTruncated());\n    }\n  }","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-bos/src/main/java/org/apache/hadoop/fs/bos/HierarchyBosNativeFileSystemStore.java#L97-L133","documentation":"Thrown by HierarchyBosNativeFileSystemStore.deleteDirs when a non-recursive delete is requested on a directory that still contains entries. The store lists up to 1 child under the key and, if any file or subdirectory is found, refuses the delete with IOException 'Directory <key> is not empty.' This mirrors the POSIX rmdir/HDFS semantics on the BOS hierarchy store.","triggerScenarios":"Calling FileSystem.delete(path, false) on a BOS directory whose listing returns at least one file or subdirectory; e.g. cleanup code that deletes job output directories non-recursively, or exists()+delete() sequences copied from local-FileSystem code.","commonSituations":"Job cleanup after a failed run leaves _temporary subdirectories; distcp or Hive scripts that issue non-recursive deletes of directories that were populated concurrently; code ported from a filesystem where delete() silently recursed.","solutions":["Call delete(path, true) to delete the directory recursively","List children first (fs.listStatus(path)) and delete them explicitly if you truly need per-entry control","Guard the non-recursive call with an emptiness check and surface a clear message to the caller"],"exampleFix":"// before\nfs.delete(new Path(\"bosn://bucket/out\"), false); // throws: dir not empty\n// after\nPath dir = new Path(\"bosn://bucket/out\");\nif (fs.getFileStatus(dir).isDirectory() && fs.listStatus(dir).length > 0) {\n  fs.delete(dir, true);\n} else {\n  fs.delete(dir, false);\n}","handlingStrategy":"validation","validationCode":"Path dir = new Path(\"bosn://bucket/out\");\nif (!fs.getFileStatus(dir).isDirectory()\n    || fs.listStatus(dir).length == 0) {\n  fs.delete(dir, false); // safe: absent or empty\n} else {\n  fs.delete(dir, true);\n}","typeGuard":null,"tryCatchPattern":"catch (IOException e) { if (e.getMessage().contains(\"is not empty\")) { /* retry recursive or report */ } else throw e; }","preventionTips":["Default to recursive delete for object-store directories","Treat non-recursive delete as an assertion of emptiness, not a cleanup call"],"tags":["bos","hadoop","delete","directory","non-recursive"],"backgroundTag":"directory-not-empty","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}