Summary
OkapiMicrometerAutoConfiguration (in okapi-spring-boot) declares @AutoConfigureAfter against the Spring Boot 4.0 package layout. On Spring Boot 3.5.x — which the README lists as supported — that class does not exist, the hint is silently dropped, and the auto-config can be evaluated before MeterRegistry is registered. When that happens, @ConditionalOnBean(MeterRegistry::class) fails and the entire auto-config (listener, metrics, refresher) is skipped — leaving consumers without metrics and breaking any code that depends on MicrometerOutboxListener.
Affected versions
- okapi
0.2.0 (and likely earlier — bug is in okapi-spring-boot)
- Spring Boot
3.5.x (verified on 3.5.7)
- README compatibility matrix says:
Spring Boot 3.5.x, 4.0.x
Symptoms
In a Spring Boot 3.5.x application with okapi-spring-boot + okapi-micrometer on the classpath and a working MeterRegistry (e.g. micrometer-registry-prometheus):
- No
okapi_* metrics appear at /actuator/prometheus.
MicrometerOutboxListener, MicrometerOutboxMetrics, OutboxMetricsRefresher beans are absent.
- Application code that injects any of these fails at startup with
UnsatisfiedDependencyException.
Root cause
OkapiMicrometerAutoConfiguration.kt:
@AutoConfiguration
@AutoConfigureAfter(
name = ["org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration"],
)
@ConditionalOnClass(name = ["io.micrometer.core.instrument.MeterRegistry"])
@ConditionalOnBean(MeterRegistry::class)
@EnableConfigurationProperties(OkapiMetricsProperties::class)
class OkapiMicrometerAutoConfiguration { ... }
The referenced class lives at org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration only in Spring Boot 4.0. In 3.5.x the same class is at org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration.
@AutoConfigureAfter(name = ...) is tolerant of missing classes — the hint is silently ignored, leaving the relative ordering between OkapiMicrometerAutoConfiguration and Spring Boot's metrics auto-configurations undefined. In practice on 3.5.7 our auto-config is evaluated before MeterRegistry is registered, so @ConditionalOnBean(MeterRegistry::class) fails and the whole class is skipped.
Reproduction
Minimal reproducer: Spring Boot 3.5.7 application with spring-boot-starter-actuator, micrometer-registry-prometheus, and the okapi BOM dependencies (okapi-core, okapi-postgres, okapi-http, okapi-spring-boot, okapi-micrometer).
- Configure a
DataSource and provide an HttpMessageDeliverer bean.
- Start the app.
curl http://localhost:8080/actuator/prometheus | grep okapi_ — empty.
- Try injecting
MicrometerOutboxListener anywhere — Spring fails with:
Parameter 0 of method X required a bean of type 'com.softwaremill.okapi.micrometer.MicrometerOutboxListener' that could not be found.
The condition evaluation report (--debug) shows OkapiMicrometerAutoConfiguration did not match because of @ConditionalOnBean(MeterRegistry::class), even though MeterRegistry is present in the running context.
Expected behavior
On any version of Spring Boot listed in the README compatibility matrix, OkapiMicrometerAutoConfiguration should be evaluated after the auto-configuration that registers MeterRegistry, so that @ConditionalOnBean(MeterRegistry::class) reliably matches.
Proposed fix
@AutoConfigureAfter(name = ...) accepts an array — list both packages so the hint is honored on either Spring Boot major version:
@AutoConfigureAfter(
name = [
// Spring Boot 3.5.x
"org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration",
// Spring Boot 4.0.x
"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration",
],
)
Spring Boot ignores missing class names per entry, so listing both is safe across versions — whichever is on the classpath wins, and the hint is honored on every supported runtime.
Workaround in the meantime
Manually register the listener in user code; ordinary @Configuration is processed after auto-configurations, so MeterRegistry is always available:
@Configuration
class OkapiWorkaroundConfig {
@Bean
fun micrometerOutboxListener(registry: MeterRegistry): MicrometerOutboxListener =
MicrometerOutboxListener(registry)
}
(Doesn't recover MicrometerOutboxMetrics/OutboxMetricsRefresher — gauges remain unavailable until the auto-config fix lands.)
Summary
OkapiMicrometerAutoConfiguration(inokapi-spring-boot) declares@AutoConfigureAfteragainst the Spring Boot 4.0 package layout. On Spring Boot 3.5.x — which the README lists as supported — that class does not exist, the hint is silently dropped, and the auto-config can be evaluated beforeMeterRegistryis registered. When that happens,@ConditionalOnBean(MeterRegistry::class)fails and the entire auto-config (listener, metrics, refresher) is skipped — leaving consumers without metrics and breaking any code that depends onMicrometerOutboxListener.Affected versions
0.2.0(and likely earlier — bug is inokapi-spring-boot)3.5.x(verified on3.5.7)Spring Boot 3.5.x, 4.0.xSymptoms
In a Spring Boot 3.5.x application with
okapi-spring-boot+okapi-micrometeron the classpath and a workingMeterRegistry(e.g.micrometer-registry-prometheus):okapi_*metrics appear at/actuator/prometheus.MicrometerOutboxListener,MicrometerOutboxMetrics,OutboxMetricsRefresherbeans are absent.UnsatisfiedDependencyException.Root cause
OkapiMicrometerAutoConfiguration.kt:@AutoConfiguration @AutoConfigureAfter( name = ["org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration"], ) @ConditionalOnClass(name = ["io.micrometer.core.instrument.MeterRegistry"]) @ConditionalOnBean(MeterRegistry::class) @EnableConfigurationProperties(OkapiMetricsProperties::class) class OkapiMicrometerAutoConfiguration { ... }The referenced class lives at
org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfigurationonly in Spring Boot 4.0. In 3.5.x the same class is atorg.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration.@AutoConfigureAfter(name = ...)is tolerant of missing classes — the hint is silently ignored, leaving the relative ordering betweenOkapiMicrometerAutoConfigurationand Spring Boot's metrics auto-configurations undefined. In practice on 3.5.7 our auto-config is evaluated beforeMeterRegistryis registered, so@ConditionalOnBean(MeterRegistry::class)fails and the whole class is skipped.Reproduction
Minimal reproducer: Spring Boot 3.5.7 application with
spring-boot-starter-actuator,micrometer-registry-prometheus, and the okapi BOM dependencies (okapi-core,okapi-postgres,okapi-http,okapi-spring-boot,okapi-micrometer).DataSourceand provide anHttpMessageDelivererbean.curl http://localhost:8080/actuator/prometheus | grep okapi_— empty.MicrometerOutboxListeneranywhere — Spring fails with:The condition evaluation report (
--debug) showsOkapiMicrometerAutoConfigurationdid not match because of@ConditionalOnBean(MeterRegistry::class), even thoughMeterRegistryis present in the running context.Expected behavior
On any version of Spring Boot listed in the README compatibility matrix,
OkapiMicrometerAutoConfigurationshould be evaluated after the auto-configuration that registersMeterRegistry, so that@ConditionalOnBean(MeterRegistry::class)reliably matches.Proposed fix
@AutoConfigureAfter(name = ...)accepts an array — list both packages so the hint is honored on either Spring Boot major version:@AutoConfigureAfter( name = [ // Spring Boot 3.5.x "org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration", // Spring Boot 4.0.x "org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration", ], )Spring Boot ignores missing class names per entry, so listing both is safe across versions — whichever is on the classpath wins, and the hint is honored on every supported runtime.
Workaround in the meantime
Manually register the listener in user code; ordinary
@Configurationis processed after auto-configurations, soMeterRegistryis always available:(Doesn't recover
MicrometerOutboxMetrics/OutboxMetricsRefresher— gauges remain unavailable until the auto-config fix lands.)