apache/druid · error · RE
Extension [ ] has a circular druid extension dependency…
Error message
Extension [%s] has a circular druid extension dependency. Dependency stack [%s].
What it means
While building classloaders for extension dependencies, ExtensionsLoader tracks the dependency stack and throws this RE when an extension's dependency chain loops back onto an extension already in the stack. Circular druid extension dependencies cannot be classloaded.
Solutions
- Edit the druid-extension-dependencies.json of one of the extensions to remove the cycle
- Restructure: move shared code into a common extension that both depend on, instead of depending on each other
- Check the printed dependency stack to identify the exact loop and which declaration to drop
- Downgrade/replace one extension with a version without the circular declaration
Example fix
// before (ext-B deps)
{"druid.extension.dependencies":["ext-A"]} // ext-A deps: ["ext-B"]
// after
{"druid.extension.dependencies":[]} Defensive patterns
Strategy: validation
Validate before calling
void checkAcyclic(Map<String,List<String>> deps) {
for (String start : deps.keySet()) {
Set<String> seen = new HashSet<>();
Deque<String> stack = new ArrayDeque<>(List.of(start));
while (!stack.isEmpty()) {
String cur = stack.pop();
if (!seen.add(cur)) throw new IllegalStateException("Cycle at " + cur);
deps.getOrDefault(cur, List.of()).forEach(stack::push);
}
}
} Try / catch
try { getClassLoaderForExtension(ext); } catch (RE e) {
if (e.getMessage().contains("circular druid extension dependency")) { log.error(e.getMessage()); }
throw e;
} Prevention
- Draw the extension dependency graph before adding new declarations
- Never declare A depends-on B and B depends-on A; factor shared code out
- Review druid-extension-dependencies.json changes in code review
When it happens
Trigger: Extension A depends on B and B depends (directly or transitively) on A; when getClassLoaderForExtension resolves the chain, the dependency name reappears in the current stack.
Common situations: Hand-edited druid-extension-dependencies.json files creating a mutual dependency; refactoring extensions into multiple modules and leaving stale dependency entries; third-party extensions from different vendors each claiming the other as a dependency.
Related errors
- Extension [ ] depends on [ ] which is not a valid extension…
- Extension [ ] specified in "druid.extensions.loadList"…
- Failed to find MariaDB driver class. Please check the…
- Failed to find MySQL driver class. Please check the MySQL…
- Failed to get dependencies for extension
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/927f529cde9080cd.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/guice/ExtensionsLoader.java:293
List<ClassLoader> extensionDependencyClassLoaders = new ArrayList<>();
for (String druidExtensionDependencyName : druidExtensionDependenciesList) {
Optional<File> extensionDependencyFileOptional = Arrays.stream(getExtensionFilesToLoad())
.filter(file -> file.getName().equals(druidExtensionDependencyName))
.findFirst();
if (!extensionDependencyFileOptional.isPresent()) {
throw new RE(
StringUtils.format(
"Extension [%s] depends on [%s] which is not a valid extension or not loaded.",
extension.getName(),
druidExtensionDependencyName
)
);
}
File extensionDependencyFile = extensionDependencyFileOptional.get();
if (extensionDependencyStack.contains(extensionDependencyFile.getName())) {
extensionDependencyStack.add(extensionDependencyFile.getName());
throw new RE(
StringUtils.format(
"Extension [%s] has a circular druid extension dependency. Dependency stack [%s].",
extensionDependencyStack.get(0),
extensionDependencyStack
)
);
}
extensionDependencyStack.add(extensionDependencyFile.getName());
extensionDependencyClassLoaders.add(
getClassLoaderForExtension(extensionDependencyFile, useExtensionClassloaderFirst, extensionDependencyStack)
);
}
return makeClassLoaderForExtension(extension, useExtensionClassloaderFirst, extensionDependencyClassLoaders);
}
private static StandardURLClassLoader makeClassLoaderForExtension(
final File extension,View on GitHub (pinned to 9b90983fd2)