apache/druid · error · IllegalArgumentException

Invalid path: [ ], should contain '/

Error message

Invalid path: [%s], should contain '/'

What it means

DataSegmentKiller.descriptorPath derives the descriptor.json location from a segment's storage path by replacing the last path component. If the path contains no '/' separator at all it cannot locate a parent directory, so it throws IAE indicating the path is invalid for descriptor lookup.

Solutions

  1. Ensure the segment path stored in the metadata store is a full deep-storage path with '/' separators
  2. Fix the LoadSpec or storage key construction that produced the separator-less path
  3. Re-upload or repair the segment entry in the segments table with a correct path

Example fix

// before
String path = "index.zip"; // no separator
String desc = DataSegmentKiller.descriptorPath(path); // throws
// after
String path = "s3://bucket/druid/segments/ds/2020-01-01/seg/index.zip";
String desc = DataSegmentKiller.descriptorPath(path); // .../seg/descriptor.json
Defensive patterns

Strategy: validation

Validate before calling

if (path == null || !path.contains("/")) throw new IllegalArgumentException("Segment path must be a full deep-storage path: " + path);

Type guard

boolean isDeepStoragePath(String p) { return p != null && p.lastIndexOf('/') > 0; }

Try / catch

try { String desc = DataSegmentKiller.descriptorPath(path); } catch (IAE e) { log.error("Bad segment path in metadata: %s", path); throw e; }

Prevention

When it happens

Trigger: Calling DataSegmentKiller APIs (or descriptorPath directly) with a segment storage path lacking any '/', e.g. a bare filename or a misconfigured single-component deep storage key.

Common situations: Custom LoadSpec/UriExtractionStrategy producing paths without separators; hand-editing segment metadata paths; deep storage emulators that flatten keys.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/b49646c8db52c48a. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/loading/DataSegmentKiller.java:46

import java.util.List;

/**
 * DataSegmentKiller knows how to kill segments from the Druid system.
 * Since any implementation of DataSegmentKiller is initialized when an ingestion job starts
 * if a deep storage extension is loaded even when that deep storage is actually not used,
 * implementations should avoid initializing the deep storage client immediately
 * but defer it until the deep storage client is actually used.
 */
@ExtensionPoint
public interface DataSegmentKiller
{
  Logger log = new Logger(DataSegmentKiller.class);

  static String descriptorPath(String path)
  {
    int lastPathSeparatorIndex = path.lastIndexOf('/');
    if (lastPathSeparatorIndex == -1) {
      throw new IAE("Invalid path: [%s], should contain '/'", path);
    }
    return path.substring(0, lastPathSeparatorIndex) + "/descriptor.json";
  }

  /**
   * Removes segment files (index and metadata) from deep storage.
   * @param segment the segment to kill
   * @throws SegmentLoadingException if the segment could not be completely removed
   */
  void kill(DataSegment segment) throws SegmentLoadingException;

  /**
   * Kills a list of segments from deep storage. The default implementation calls kill on the segments in a loop.
   * Implementers of this interface can leverage batch / bulk deletes to be more efficient. It is preferable to attempt
   * to delete all segments even if there is an issue with deleting a single one. This is up to implementers to
   * implement as putting a try catch around the default kill via iteration can be problematic if the client of the deep
   * storage is unable to authenticate itself and segment loading exception doesn't encode enough information in it to \
   * understand why it failed.

View on GitHub (pinned to 9b90983fd2)