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

  1. Add `uses <fully.qualified.ProviderType>;` to the module-info.java of the module that constructs the ProviderLocator.
  2. Confirm the fully-qualified name in `uses` exactly matches the Class passed to ProviderLocator (including package).
  3. If the call site moved to a different module, add the uses directive to that module instead.
  4. 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

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


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/696ed03ea0b7c08f. Report an issue: GitHub.