{"record":{"id":"6f40a4bbe0e41caf","repo":"apache/druid","slug":"skipping-deep-storage-directory-kill-relative-pat","errorCode":null,"errorMessage":"Skipping deep storage directory kill: relative path is empty","messagePattern":"Skipping deep storage directory kill: relative path is empty","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"extensions-core/hdfs-storage/src/main/java/org/apache/druid/storage/hdfs/HdfsDataSegmentKiller.java","lineNumber":183,"sourceCode":"    final FileSystem fs = dirToDelete.getFileSystem(config);\n    if (!fs.exists(dirToDelete)) {\n      return;\n    }\n    log.info(\"Deleting deep storage directory[%s]\", dirToDelete);\n    if (!fs.delete(dirToDelete, true)) {\n      throw new IOException(\"Failed to delete deep storage directory[\" + dirToDelete + \"].\");\n    }\n  }\n\n  /**\n   * Construct a path to delete from HDFS. Returns null if the path is invalid.\n   * Replicates how {@link HdfsDataSegmentPusher#pushToPath} handles ':', by replacing that with '_'.\n   */\n  @Nullable\n  private Path constructHdfsDeletePath(String relativePath)\n  {\n    if (Strings.isNullOrEmpty(relativePath)) {\n      log.warn(\"Skipping deep storage directory kill: relative path is empty\");\n      return null;\n    }\n    if (relativePath.charAt(0) == '/') {\n      log.warn(\"Skipping deep storage directory kill: relative path must not be absolute, got [%s]\", relativePath);\n      return null;\n    }\n    if (relativePath.indexOf('\\\\') >= 0) {\n      log.warn(\"Skipping deep storage directory kill: backslash not allowed in path [%s]\", relativePath);\n      return null;\n    }\n    for (String segment : StringUtils.splitPreserveAllTokens(relativePath, '/')) {\n      if (segment.isEmpty() || \"..\".equals(segment)) {\n        log.warn(\"Skipping deep storage directory kill: invalid path[%s]\", relativePath);\n        return null;\n      }\n    }\n\n    if (storageDirectory == null) {","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/hdfs-storage/src/main/java/org/apache/druid/storage/hdfs/HdfsDataSegmentKiller.java#L165-L201","documentation":"constructHdfsDeletePath validates the segment's relative path before building an HDFS delete Path. If the relative path is null or empty it logs this warning and returns null, causing the kill to be skipped rather than attempting a dangerous or meaningless delete of the storage root.","triggerScenarios":"A DataSegment whose loadSpec path (relative portion after the storage directory) is empty — typically a segment with a malformed or minimal loadSpec passed to dirToDelete/kill.","commonSituations":"Segments loaded from old Druid versions or external ingestion that wrote segments without a proper path, or custom deep-storage adapters producing segments with empty paths.","solutions":["Inspect the offending segment's loadSpec in metadata store to find why the path is empty","Re-push or re-ingest the affected segments so a valid relative path is stored","Skip the kill for such segments; the guard is intentional protection against deleting the whole storage directory"],"exampleFix":"// before\nif (Strings.isNullOrEmpty(relativePath)) { log.warn(\"Skipping deep storage directory kill: relative path is empty\"); return null; }\n// after\nif (Strings.isNullOrEmpty(relativePath)) {\n  log.warnEvents(\"Skipping deep storage directory kill: relative path is empty for segment [%s]\", segment.getIdentifier());\n  return null;\n}","handlingStrategy":"validation","validationCode":"if (segmentPath == null || segmentPath.isEmpty()) {\n  throw new IllegalArgumentException(\"segment relative path must not be empty\");\n}","typeGuard":"static boolean hasNonEmptyRelativePath(DataSegment s) {\n  Object p = s.getLoadSpec().get(\"path\");\n  return p instanceof String && !((String) p).isEmpty();\n}","tryCatchPattern":null,"preventionTips":["Validate segment loadSpecs on ingestion","Watch for segments pushed by custom adapters","Re-push segments with empty paths instead of killing them"],"tags":["hdfs","segment-kill","path-validation","druid"],"backgroundTag":"empty-required-field","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}