Skip to content

Conversation

@genuss
Copy link
Contributor

@genuss genuss commented Nov 10, 2025

Answering a bit late on the question in #282

As it was mentioned in #283 the issue is caused by context-propagation missing on a classpath. The root-cause is a bit deeper. If observation is configured spring-grpc will create a ObservationCoroutineContextServerInterceptor bean specifically for kotlin coroutine-based servers. Although this class doesn't require context-propagation directly, its dependency KotlinObservationContextElement does. That's why the kotlin-sample server starts, but then it fails to process a request silently. Enabling the logs gives the root-cause:

2025-11-10T16:29:19.911+01:00 ERROR 27640 --- [grpc-server-kotlin] [ault-executor-0] eptionHandlerInterceptor$FallbackHandler : Unknown exception

java.lang.NoClassDefFoundError: io/micrometer/context/ContextRegistry
	at io.micrometer.core.instrument.kotlin.AsContextElementKt.asContextElement(AsContextElement.kt:31) ~[micrometer-core-1.16.0-RC1.jar:1.16.0-RC1]
	at io.micrometer.core.instrument.kotlin.ObservationCoroutineContextServerInterceptor.coroutineContext(ObservationCoroutineContextServerInterceptor.kt:45) ~[micrometer-core-1.16.0-RC1.jar:1.16.0-RC1]
	at io.grpc.kotlin.CoroutineContextServerInterceptor.interceptCall(CoroutineContextServerInterceptor.kt:61) ~[grpc-kotlin-stub-1.5.0.jar:na]
	at io.grpc.ServerInterceptors$InterceptCallHandler.startCall(ServerInterceptors.java:269) ~[grpc-api-1.76.0.jar:1.76.0]
	at io.micrometer.core.instrument.binder.grpc.ObservationGrpcServerInterceptor.interceptCall(ObservationGrpcServerInterceptor.java:124) ~[micrometer-core-1.16.0-RC1.jar:1.16.0-RC1]
	at io.grpc.ServerInterceptors$InterceptCallHandler.startCall(ServerInterceptors.java:269) ~[grpc-api-1.76.0.jar:1.76.0]
	at org.springframework.grpc.server.exception.GrpcExceptionHandlerInterceptor.interceptCall(GrpcExceptionHandlerInterceptor.java:74) ~[classes/:na]
	at io.grpc.ServerInterceptors$InterceptCallHandler.startCall(ServerInterceptors.java:269) ~[grpc-api-1.76.0.jar:1.76.0]
	at io.grpc.internal.ServerImpl$ServerTransportListenerImpl.startWrappedCall(ServerImpl.java:701) ~[grpc-core-1.76.0.jar:1.76.0]
	at io.grpc.internal.ServerImpl$ServerTransportListenerImpl.access$2200(ServerImpl.java:408) ~[grpc-core-1.76.0.jar:1.76.0]
	at io.grpc.internal.ServerImpl$ServerTransportListenerImpl$1HandleServerCall.runInternal(ServerImpl.java:613) ~[grpc-core-1.76.0.jar:1.76.0]
	at io.grpc.internal.ServerImpl$ServerTransportListenerImpl$1HandleServerCall.runInContext(ServerImpl.java:603) ~[grpc-core-1.76.0.jar:1.76.0]
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) ~[grpc-core-1.76.0.jar:1.76.0]
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133) ~[grpc-core-1.76.0.jar:1.76.0]
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[na:na]
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[na:na]
	at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Caused by: java.lang.ClassNotFoundException: io.micrometer.context.ContextRegistry
	... 17 common frames omitted

In RC1 spring-boot-starter-actuator provided context-propagation via spring-boot-micrometer-tracing, but it's not the case anymore, see spring-projects/spring-boot#47785.

Given all that, I propose a safe solution: don't create a ObservationCoroutineContextServerInterceptor bean if context-propagation isn't available.

…ometer context-propagation isn't present on classpath

Signed-off-by: Alexey Genus <genus.alexey@gmail.com>
@genuss genuss force-pushed the micrometer-ctx-propagation branch from 11c7ac9 to ae0babe Compare November 10, 2025 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant