apache/druid · error · SegmentLoadingException
Unknown segment killer type
Error message
Unknown segment killer type[%s]. Known types are %s
What it means
OmniDataSegmentKiller.getKiller throws SegmentLoadingException when the segment's loadSpec 'type' has no registered DataSegmentKiller. The killer dispatcher needs a killer per deep-storage type to delete segment files; an unknown type means Druid cannot delete that segment's data.
Solutions
- Load the extension matching the loadSpec type in druid.extensions.loadList and restart.
- Inspect the segment's loadSpec in the metadata store (druid_segments table) to confirm the 'type' value.
- Fix typo'd/null 'type' entries with a metadata update or re-push affected segments.
- Manually delete orphaned data files and drop the segment rows if the old backend is retired.
Example fix
// before: killers for 'local' only, segments typed 'hdfs' # druid.extensions.loadList=["druid-lookups-cached-global"] // after # druid.extensions.loadList=["druid-lookups-cached-global","druid-hdfs-storage"]
Defensive patterns
Strategy: validation
Validate before calling
String type = (String) segment.getLoadSpec().get("type");
if (type == null || !registeredKillerTypes.contains(type)) {
throw new IllegalStateException("no killer for loadSpec type " + type);
} Type guard
boolean killable(DataSegment segment) {
Object t = segment.getLoadSpec().get("type");
return t instanceof String && knownTypes.contains(t);
} Try / catch
try {
killer.kill(segment);
} catch (SegmentLoadingException e) {
log.error(e, "cannot kill segment %s: unsupported storage type %s", segment.getId(), segment.getLoadSpec().get("type"));
// fail kill task so coordinator retries after extension is added
} Prevention
- Install the storage extension on overlord/coordinator nodes, not just historicals, so kill tasks can delete data.
- When migrating deep-storage types, drain and kill old-type segments before removing the extension.
- Audit the metadata store for null/typo'd loadSpec types after upgrades.
- Keep druid.extensions.loadList identical across all Druid service roles.
When it happens
Trigger: dataSegmentKiller(segment) called (via kill tasks or coordinator kill) with a loadSpec type not present in the killers map — extension not loaded, typo'd type, or null 'type' in loadSpec.
Common situations: Kill tasks failing after storage-type migration; metadata store contains segments from a storage backend whose extension is missing on the coordinator/overlord; hand-edited loadSpecs; upgrades that renamed a storage type.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Skipping deep storage directory kill: storage directory not…
- Unknown loader type[ ]. Known types are
- A valid tlsPort needs to specified when druid.enableTlsPort…
- At least one of the druid.enablePlaintextPort or…
- At least one task runner must be enabled
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/7733940d62bfdc84.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/main/java/org/apache/druid/segment/loading/OmniDataSegmentKiller.java:91
public void kill(DataSegment segment) throws SegmentLoadingException
{
DataSegmentKiller dataSegmentKiller = getKiller(segment);
if (dataSegmentKiller != null) {
dataSegmentKiller.kill(segment);
}
}
@Nullable
private DataSegmentKiller getKiller(DataSegment segment) throws SegmentLoadingException
{
if (segment.isTombstone()) {
return null;
}
String type = MapUtils.getString(segment.getLoadSpec(), "type");
Supplier<DataSegmentKiller> killer = killers.get(type);
if (killer == null) {
throw new SegmentLoadingException("Unknown segment killer type[%s]. Known types are %s", type, killers.keySet());
}
return killer.get();
}
@Override
public void killAll()
{
throw new UnsupportedOperationException("not implemented");
}
@Override
public void killRecursively(String relativePath) throws IOException
{
IOException firstFailure = null;
for (Supplier<DataSegmentKiller> supplier : killers.values()) {
try {
supplier.get().killRecursively(relativePath);View on GitHub (pinned to 9b90983fd2)