quarkusio/quarkus · error · IllegalArgumentException

Use GeneratedServiceProviderBuildItem to register service pr

Error message

Use GeneratedServiceProviderBuildItem to register service providers instead of GeneratedResourceBuildItem, or use GeneratedResourceBuildItem.allowingMetaInfServices(...) if your ${name} resource is not a service provider

What it means

GeneratedResourceBuildItem is for generated application resources; META-INF/services/ entries, however, are service provider registrations and must go through GeneratedServiceProviderBuildItem so Quarkus can index and handle them correctly. Since this guard was introduced, emitting a generated resource under META-INF/services/ through the plain resource item throws IllegalArgumentException, telling you which item to use instead.

Source

Thrown at core/deployment/src/main/java/io/quarkus/deployment/builditem/GeneratedResourceBuildItem.java:43

    public GeneratedResourceBuildItem(String name, byte[] data) {
        this(name, data, false);
    }

    /**
     * @deprecated Use {@link GeneratedResourceBuildItem#GeneratedResourceBuildItem(String, byte[])} instead.
     *             If you want to serve static resources use
     *             {@link io.quarkus.vertx.http.deployment.spi.GeneratedStaticResourceBuildItem}
     *             instead.
     */
    @Deprecated(since = "4.0", forRemoval = true)
    public GeneratedResourceBuildItem(String name, byte[] data, boolean excludeFromDevCL) {
        this(name, data, excludeFromDevCL, false);
    }

    private GeneratedResourceBuildItem(String name, byte[] data, boolean excludeFromDevCL,
            boolean allowMetaInfServices) {
        if (name.startsWith("META-INF/services/") && !allowMetaInfServices) {
            throw new IllegalArgumentException(
                    "Use GeneratedServiceProviderBuildItem to register service providers instead of GeneratedResourceBuildItem, or use GeneratedResourceBuildItem.allowingMetaInfServices(...) if your "
                            + name + " resource is not a service provider");
        }
        this.name = name;
        this.data = data;
        this.excludeFromDevCL = excludeFromDevCL;
    }

    /**
     * Use only for {@code META-INF/services/} resources with a non-standard format incompatible with
     * {@link GeneratedServiceProviderBuildItem}. Prefer {@link GeneratedServiceProviderBuildItem} for standard
     * Java {@link java.util.ServiceLoader} registrations.
     */
    public static GeneratedResourceBuildItem allowingMetaInfServices(String name, byte[] data) {
        return new GeneratedResourceBuildItem(name, data, false, true);
    }

    public String getName() {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Replace the item with new GeneratedServiceProviderBuildItem(serviceInterfaceName, List.of(implementationClassNames)) and drop the manual descriptor bytes.
  2. If the resource genuinely is not a service provider but just happens to live under META-INF/services/, use GeneratedResourceBuildItem.allowingMetaInfServices(...) instead of the plain constructor.
  3. Update related build steps that consume the resource item so they consume the service provider item instead.

Example fix

// before
buildProducer.produce(new GeneratedResourceBuildItem(
        "META-INF/services/com.acme.MySpi",
        implClass.getBytes(StandardCharsets.UTF_8)));
// after
buildProducer.produce(new GeneratedServiceProviderBuildItem(
        "com.acme.MySpi", List.of("com.acme.MySpiImpl")));
Defensive patterns

Strategy: validation

Validate before calling

void produceGenerated(BuildProducer<GeneratedResourceBuildItem> out, String name, byte[] data) {
    if (name.startsWith("META-INF/services/")) {
        throw new IllegalArgumentException("Use GeneratedServiceProviderBuildItem for " + name);
    }
    out.produce(new GeneratedResourceBuildItem(name, data));
}

Type guard

boolean isServiceProviderResource(String name) {
    return name != null && name.startsWith("META-INF/services/");
}

Try / catch

try {
    out.produce(new GeneratedResourceBuildItem(name, data));
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("GeneratedServiceProviderBuildItem")) {
        String svc = name.substring("META-INF/services/".length());
        serviceProviderProducer.produce(new GeneratedServiceProviderBuildItem(svc, List.of(implClassName)));
        return;
    }
    throw e;
}

Prevention

When it happens

Trigger: Producing new GeneratedResourceBuildItem("META-INF/services/io.quarkus...", bytes) in a build step without using GeneratedResourceBuildItem.allowingMetaInfServices(...) or switching to GeneratedServiceProviderBuildItem.

Common situations: Older extensions that predate the dedicated service-provider build item; code migrating from raw resource emission for ServiceLoader files; copy-pasted build-step code writing service descriptors.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/dff2f4b1c14adec0. Report an issue: GitHub.