#50244·keycloak

Creating a custom 'EventStoreProvider' implementation with order() < 0 results in a NPE

Author: rtufisiCreated Jun 23, 2026Updated Sep 17, 2026
Labelskind/bugarea/corehelp wantedteam/core-sharedpriority/lowstatus/auto-bumpteam/core-protocols

Before reporting an issue

  • I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.

Area

core

Describe the bug

The guide for selecting a default provider for an SPI states (point 2):

The provider with the highest order (providers with order ⇐ 0 are ignored)

https://www.keycloak.org/server/configuration-provider#_configuring_a_default_provider_for_an_spi

I built an extension: a custom EventStoreProvider (id ext-mongo). The goal is for the built-in jpa provider to remain the default events store, and for my provider to be used only when it is explicitly selected, e.g. KC_SPI_EVENTS_STORE__PROVIDER=ext-mongo (--spi-events-store--provider=ext-mongo).

Following the documented rule, I gave my factory a non-positive order so it would be "ignored" for default selection and not disturb the existing default:

java
@Override
public int order() {
  return -1;
}

Based on the wording "providers with order ⇐ 0 are ignored", I expected my provider to simply not participate in default selection, leaving jpa as the default. Instead, as soon as my provider is registered (and no explicit spi-events-store-provider is set), the SPI ends up with no default provider, and the events endpoint throws an uncaught NPE:

java.lang.NullPointerException: Cannot invoke "org.keycloak.events.EventStoreProvider.createQuery()" because "eventStore" is null
    at org.keycloak.services.resources.admin.RealmAdminResource.getEvents(RealmAdminResource.java:907)

So the provider with order() <= 0 is ignored exactly as documented — but "ignored" should not also mean "removes the built-in default and leaves the SPI with none." And regardless of the resolution outcome, a null default should not surface as an uncaught NPE on a REST endpoint.

Version

26.6.2

Regression

  • The issue is a regression

Expected behavior

A registered factory with order() <= 0 is truly ignored, so the remaining qualifying built-in (jpa) stays the default. This matches the documented wording and lets an extension ship as opt-in-only — selectable by id via spi-events-store-provider, without becoming or breaking the default.

There should be a supported way to deploy an additional EventStoreProvider that does not become the default and does not disturb the built-in jpa default, used only when explicitly selected.

Actual behavior

Registering a second EventStoreProvider factory with order() <= 0 and no explicit spi-events-store-provider leaves the SPI with no default provider.

GET /admin/realms/{realm}/events (and the Admin Console Events view) throws an uncaught NullPointerException because session.getProvider(EventStoreProvider.class) is null.

How to Reproduce?

  1. Implement a custom EventStoreProviderFactory (id ext-mongo), registered via @AutoService / META-INF/services, with order() returning -1.
  2. Build the jar, place it in providers/, and start Keycloak without setting spi-events-store-provider / KC_SPI_EVENTS_STORE__PROVIDER. 3 .Open the realm's Events view in the Admin Console.
  3. Observe the 500 / NullPointerException above.

Expected: the built-in jpa store is used and events load, since the custom provider declared order() <= 0 and should be ignored.

Anything else?

No response