elastic/elasticsearch · error · ServiceConfigurationError
%s: module does not declare uses %s
Error message
%s: module does not declare uses %s
What it means
Thrown as a ServiceConfigurationError by ProviderLocator.checkUses when the module owning the provider type is a named module but its descriptor does not declare a `uses` directive for that provider type. Java's ServiceLoader contract requires a module to declare `uses <service>` before it can load providers for that service; ProviderLocator enforces this eagerly at construction so the failure surfaces at the locator call site rather than later during loading.
Source
Thrown at libs/core/src/main/java/org/elasticsearch/core/internal/provider/ProviderLocator.java:55
*/
public final class ProviderLocator<T> implements Supplier<T> {
private final String providerName;
private final Class<T> providerType;
private final String providerModuleName;
private final ClassLoader parentLoader;
private final Set<String> missingModules;
// whether to load the provider implementation as a module or not
private final boolean loadAsProviderModule;
/** Checks that the module of the given type declares that it uses said type. */
static <P> Class<P> checkUses(Class<P> providerType) {
Module caller = providerType.getModule();
if (caller.isNamed() && caller.getDescriptor().uses().stream().anyMatch(providerType.getName()::equals) == false) {
throw new ServiceConfigurationError(String.format(Locale.ROOT, "%s: module does not declare uses %s", caller, providerType));
}
return providerType;
}
public ProviderLocator(String providerName, Class<T> providerType, String providerModuleName, Set<String> missingModules) {
this(
providerName,
checkUses(providerType),
ProviderLocator.class.getClassLoader(),
providerModuleName,
missingModules,
ProviderLocator.class.getModule().isNamed()
);
}
// package-private for testing
ProviderLocator(
String providerName,View on GitHub (pinned to db6a809a66)
Solutions
- Add `uses <fully.qualified.ProviderType>;` to the module-info.java of the module that constructs the ProviderLocator.
- Confirm the fully-qualified name in `uses` exactly matches the Class passed to ProviderLocator (including package).
- If the call site moved to a different module, add the uses directive to that module instead.
- Rebuild and re-run — module-info changes take effect at compile/load time.
Example fix
// before — module-info.java
module my.mod {
requires elasticsearch.core;
}
// after
module my.mod {
requires elasticsearch.core;
uses org.elasticsearch.xcontent.XContentProvider;
} Defensive patterns
Strategy: validation
Validate before calling
// Verify a module declares `uses` for a service type before constructing ProviderLocator
boolean declaresUses(Class<?> service) {
Module m = service.getModule();
return !m.isNamed() || m.getDescriptor().uses().contains(service.getName());
} Type guard
static boolean moduleDeclaresUses(Class<?> service) {
Module m = service.getModule();
return m.isNamed() && m.getDescriptor().uses().contains(service.getName());
} Try / catch
try {
return new ProviderLocator<>(name, type, moduleName, missingModules).get();
} catch (ServiceConfigurationError e) {
if (e.getMessage().contains("does not declare uses")) {
// fix module-info.java of the calling module to add `uses <type>;` then rebuild
throw new RuntimeException("module-info missing 'uses " + type.getName() + "'", e);
}
throw e;
} Prevention
- Add `uses <service>;` to module-info.java of any module that calls ProviderLocator/ServiceLoader.load.
- When refactoring a service type to a new package, update the uses directive in lockstep.
- Remember: the unnamed module (classpath) skips this check — engage JPMS early in tests.
- Treat ServiceConfigurationError as fatal at startup, not retried.
When it happens
Trigger: Constructing a `new ProviderLocator(name, ProviderType.class, moduleName, missingModules)` from within a named module whose module-info does not contain `uses <fully.qualified.ProviderType>`. The check at line 54 fires when the module's uses() set lacks the provider type's name.
Common situations: Adding a ServiceLoader-based provider lookup to a module but forgetting to add the `uses` directive in module-info.java. Refactoring the provider type to a new package without updating module-info. Splitting a module and dropping the uses directive. Running code that previously worked on the classpath (unnamed module — check is skipped) once the module system is engaged.
Related errors
- automatic module without a manifest name is not supported, f
- Automatic-Module-Name: {e.getMessage()}
- unexpected jar name: {jarName}
- {name} found in top-level directory (unnamed package not all
- unknown scheme:{rootURI.getScheme()}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/696ed03ea0b7c08f.
Report an issue: GitHub.