{"record":{"id":"a02db7070e9399f4","repo":"apache/druid","slug":"skipping-deep-storage-directory-kill-relative-pat-a02db7","errorCode":null,"errorMessage":"Skipping deep storage directory kill: relative path must not be absolute, got [%s]","messagePattern":"Skipping deep storage directory kill: relative path must not be absolute, got \\[(.+?)\\]","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"extensions-core/hdfs-storage/src/main/java/org/apache/druid/storage/hdfs/HdfsDataSegmentKiller.java","lineNumber":187,"sourceCode":"    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) {\n      log.warn(\"Skipping deep storage directory kill: storage directory not configured\");\n      return null;\n    }\n","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/hdfs-storage/src/main/java/org/apache/druid/storage/hdfs/HdfsDataSegmentKiller.java#L169-L205","documentation":"constructHdfsDeletePath rejects relative paths that start with '/' because an absolute path would cause the killer to delete outside (or at the root of) the configured deep-storage directory. It logs this warning and returns null, skipping the delete. This is a safety guard against misconfigured segment loadSpec paths.","triggerScenarios":"A DataSegment's loadSpec key/path begins with '/', e.g. a manually crafted segment or one pushed by a pusher configured with an absolute storage path.","commonSituations":"Mixing deep storage configs (base directory changed from relative to absolute), hand-migrated metadata rows, or segments copied between clusters with different HDFS layouts.","solutions":["Fix the segment's loadSpec path in the metadata store to be relative to druid.storage.storageDirectory","Verify druid.storage.storageDirectory config is correct and that segments were pushed by the same config","Do not work around by editing the killer; the absolute path would otherwise delete arbitrary HDFS data"],"exampleFix":"// before (metadata loadSpec)\n\"path\": \"/druid/segments/datasource/2019-01-01T00:00:00.000Z_2019-01-02T00:00:00.000Z/2020-01-01T00:00:00.000Z/0/index.zip\"\n// after\n\"path\": \"datasource/2019-01-01T00:00:00.000Z_2019-01-02T00:00:00.000Z/2020-01-01T00:00:00.000Z/0/index.zip\"","handlingStrategy":"validation","validationCode":"if (segmentPath.startsWith(\"/\")) {\n  throw new IllegalArgumentException(\"segment relative path must not be absolute: \" + segmentPath);\n}","typeGuard":"static boolean isRelativePath(String p) { return p != null && !p.startsWith(\"/\"); }","tryCatchPattern":null,"preventionTips":["Never store absolute paths in segment loadSpecs","Keep storageDirectory config consistent when migrating clusters","Validate segment metadata after manual migrations"],"tags":["hdfs","segment-kill","path-validation","security","druid"],"backgroundTag":"path-traversal-blocked","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"}