Skip to content

Kafka in native-image fails when using SSL bundles #44435

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
mhalbritter opened this issue Feb 26, 2025 · 5 comments
Closed

Kafka in native-image fails when using SSL bundles #44435

mhalbritter opened this issue Feb 26, 2025 · 5 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@mhalbritter
Copy link
Contributor

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.apache.kafka.common.config.ConfigException: Invalid value org.springframework.boot.autoconfigure.kafka.SslBundleSslEngineFactory for configuration ssl.engine.factory.class: Class org.springframework.boot.autoconfigure.kafka.SslBundleSslEngineFactory could not be found.] with root cause

org.apache.kafka.common.config.ConfigException: Invalid value org.springframework.boot.autoconfigure.kafka.SslBundleSslEngineFactory for configuration ssl.engine.factory.class: Class org.springframework.boot.autoconfigure.kafka.SslBundleSslEngineFactory could not be found.
        at org.apache.kafka.common.config.ConfigDef.parseType(ConfigDef.java:778) ~[na:na]
        at org.apache.kafka.common.config.ConfigDef.parseValue(ConfigDef.java:531) ~[na:na]
        at org.apache.kafka.common.config.ConfigDef.parse(ConfigDef.java:524) ~[na:na]
        at org.apache.kafka.common.config.AbstractConfig.<init>(AbstractConfig.java:114) ~[kafka-producer-sample:na]
        at org.apache.kafka.common.config.AbstractConfig.<init>(AbstractConfig.java:134) ~[kafka-producer-sample:na]
        at org.apache.kafka.clients.producer.ProducerConfig.<init>(ProducerConfig.java:643) ~[na:na]
        at org.apache.kafka.clients.producer.KafkaProducer.<init>(KafkaProducer.java:295) ~[na:na]
        at org.springframework.kafka.core.DefaultKafkaProducerFactory.createRawProducer(DefaultKafkaProducerFactory.java:944) ~[kafka-producer-sample:3.3.3]
        at org.springframework.kafka.core.DefaultKafkaProducerFactory.createKafkaProducer(DefaultKafkaProducerFactory.java:826) ~[kafka-producer-sample:3.3.3]
        at org.springframework.kafka.core.DefaultKafkaProducerFactory.doCreateProducer(DefaultKafkaProducerFactory.java:793) ~[kafka-producer-sample:3.3.3]
        at org.springframework.kafka.core.DefaultKafkaProducerFactory.createProducer(DefaultKafkaProducerFactory.java:768) ~[kafka-producer-sample:3.3.3]
        at org.springframework.kafka.core.DefaultKafkaProducerFactory.createProducer(DefaultKafkaProducerFactory.java:762) ~[kafka-producer-sample:3.3.3]
        at org.springframework.kafka.core.KafkaTemplate.getTheProducer(KafkaTemplate.java:976) ~[kafka-producer-sample:3.3.3]
        at org.springframework.kafka.core.KafkaTemplate.doSend(KafkaTemplate.java:828) ~[kafka-producer-sample:3.3.3]
        at org.springframework.kafka.core.KafkaTemplate.observeSend(KafkaTemplate.java:805) ~[kafka-producer-sample:3.3.3]
        at org.springframework.kafka.core.KafkaTemplate.send(KafkaTemplate.java:582) ~[kafka-producer-sample:3.3.3]
        at com.ks.kafka.sample.service.sender.Sender.send(Sender.java:18) ~[kafka-producer-sample:na]
        at com.ks.kafka.sample.service.MessageService.send(MessageService.java:16) ~[kafka-producer-sample:na]
        at com.ks.kafka.sample.controller.KafkaController.sendMessage(KafkaController.java:18) ~[kafka-producer-sample:na]
        at java.base@17.0.12/java.lang.reflect.Method.invoke(Method.java:568) ~[kafka-producer-sample:na]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:257) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:190) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:986) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:891) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[kafka-producer-sample:6.2.3]
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) ~[kafka-producer-sample:6.0]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[kafka-producer-sample:6.2.3]
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[kafka-producer-sample:6.0]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[na:na]
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[kafka-producer-sample:10.1.36]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[na:na]
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[kafka-producer-sample:6.2.3]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[na:na]
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[kafka-producer-sample:6.2.3]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[na:na]
        at org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:114) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[kafka-producer-sample:6.2.3]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[na:na]
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[kafka-producer-sample:6.2.3]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[kafka-producer-sample:6.2.3]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[na:na]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[na:na]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[na:na]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483) ~[kafka-producer-sample:10.1.36]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[na:na]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[kafka-producer-sample:10.1.36]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[na:na]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[na:na]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) ~[na:na]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[kafka-producer-sample:10.1.36]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905) ~[na:na]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743) ~[na:na]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[kafka-producer-sample:10.1.36]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190) ~[na:na]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[na:na]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[na:na]
        at java.base@17.0.12/java.lang.Thread.run(Thread.java:842) ~[kafka-producer-sample:na]
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:885) ~[kafka-producer-sample:na]
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:860) ~[kafka-producer-sample:na]

There's a runtime hint missing for org.springframework.boot.autoconfigure.kafka.SslBundleSslEngineFactory.

@mhalbritter
Copy link
Contributor Author

Workaround until this is fixed:

class MyHint implements RuntimeHintsRegistrar {
    @Override
    public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
        hints.reflection().registerType(SslBundleSslEngineFactory.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
    }
}

and @ImportRuntimeHints(MyHint.class).

@patpatpat123
Copy link

Hello @mhalbritter ,

Just wanted to say thank you for this, you beat me to this.
I reached out with the same issue here

reactor/reactor-kafka#418

and here:

#44414 (comment)

I was going to send the minimal https://github.com/patpatpat123/issuekafkasslbundle

And saw this post only after.

Again, thank you for doing this. Good day!

@patpatpat123
Copy link

patpatpat123 commented Mar 26, 2025

Hello @mhalbritter ,

Apologies for breaking the etiquette and posting on a closed thread.

Just wanted to confirm this fix should be within 3.4.4 right?

Because we just bumped everything to 3.4.4 and still seeing this issue:

i.m.c.i.binder.jvm.JvmGcMetrics : GC notifications will not be available because no GarbageCollectorMXBean of the JVM provides any. GCs=[young generation scavenger, complete scavenger]
WARNING: A restricted method in java.lang.System has been called
WARNING: java.lang.System::loadLibrary has been called by io.netty.util.internal.NativeLibraryUtil in an unnamed module (file:/workspace/com.Application)
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
WARNING: Restricted methods will be blocked in a future release unless native access is enabled

Started Application in 0.121 seconds (process running for 0.127)
o.s.c.f.c.c.BeanFactoryAwareFunctionRegistry : Failed to invoke function 'sendToKafka'
org.apache.kafka.common.config.ConfigException: Invalid value org.springframework.boot.autoconfigure.kafka.SslBundleSslEngineFactory for configuration ssl.engine.factory.class: Class org.springframework.boot.autoconfigure.kafka.SslBundleSslEngineFactory could not be found.
	at org.apache.kafka.common.config.ConfigDef.parseType(ConfigDef.java:778)
	at org.apache.kafka.common.config.ConfigDef.parseValue(ConfigDef.java:531)
	at org.apache.kafka.common.config.ConfigDef.parse(ConfigDef.java:524)
	at org.apache.kafka.common.config.AbstractConfig.<init>(AbstractConfig.java:114)
	at org.apache.kafka.common.config.AbstractConfig.<init>(AbstractConfig.java:134)
	at org.apache.kafka.clients.producer.ProducerConfig.<init>(ProducerConfig.java:643)
	at org.apache.kafka.clients.producer.KafkaProducer.<init>(KafkaProducer.java:295)
	at reactor.kafka.sender.internals.ProducerFactory.createProducer(ProducerFactory.java:34)
	at reactor.kafka.sender.internals.DefaultKafkaSender.lambda$new$2(DefaultKafkaSender.java:102)
	at reactor.core.publisher.MonoCallable.call(MonoCallable.java:72)
	at reactor.core.publisher.FluxSubscribeOnCallable$CallableSubscribeOnSubscription.run(FluxSubscribeOnCallable.java:228)
	at reactor.core.scheduler.ImmediateScheduler.schedule(ImmediateScheduler.java:52)
	at reactor.core.publisher.MonoSubscribeOnCallable.subscribe(MonoSubscribeOnCallable.java:52)
	at reactor.core.publisher.MonoCacheTime.subscribeOrReturn(MonoCacheTime.java:143)
	at reactor.core.publisher.Flux.subscribe(Flux.java:8876)
	at reactor.core.publisher.Flux.subscribeWith(Flux.java:9012)
	at reactor.core.publisher.Flux.subscribe(Flux.java:8856)
	at reactor.core.publisher.Flux.subscribe(Flux.java:8780)
	at reactor.core.publisher.Flux.subscribe(Flux.java:8698)
	at com.Service.run(Service.java:53)
	at org.springframework.boot.SpringApplication.lambda$callRunner$5(SpringApplication.java:788)
	at org.springframework.util.function.ThrowingConsumer$1.acceptWithException(ThrowingConsumer.java:82)
	at org.springframework.util.function.ThrowingConsumer.accept(ThrowingConsumer.java:60)
	at org.springframework.util.function.ThrowingConsumer$1.accept(ThrowingConsumer.java:86)
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:796)
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:787)
	at org.springframework.boot.SpringApplication.lambda$callRunners$3(SpringApplication.java:772)
	at java.base@24/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:186)
	at java.base@24/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357)
	at java.base@24/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:571)
	at java.base@24/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:560)
	at java.base@24/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:153)
	at java.base@24/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:176)
	at java.base@24/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:265)
	at java.base@24/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:636)
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:772)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:325)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350)
	at com.Application.main(Application.java:18)
	at java.base@24/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)


reactor.core.Exceptions$ErrorCallbackNotImplemented: org.apache.kafka.common.config.ConfigException: Invalid value org.springframework.boot.autoconfigure.kafka.SslBundleSslEngineFactory for configuration ssl.engine.factory.class: Class org.springframework.boot.autoconfigure.kafka.SslBundleSslEngineFactory could not be found.
Caused by: org.apache.kafka.common.config.ConfigException: Invalid value org.springframework.boot.autoconfigure.kafka.SslBundleSslEngineFactory for configuration ssl.engine.factory.class: Class org.springframework.boot.autoconfigure.kafka.SslBundleSslEngineFactory could not be found.
	at org.apache.kafka.common.config.ConfigDef.parseType(ConfigDef.java:778)
	at org.apache.kafka.common.config.ConfigDef.parseValue(ConfigDef.java:531)
	at org.apache.kafka.common.config.ConfigDef.parse(ConfigDef.java:524)
	at org.apache.kafka.common.config.AbstractConfig.<init>(AbstractConfig.java:114)
	at org.apache.kafka.common.config.AbstractConfig.<init>(AbstractConfig.java:134)
	at org.apache.kafka.clients.producer.ProducerConfig.<init>(ProducerConfig.java:643)
	at org.apache.kafka.clients.producer.KafkaProducer.<init>(KafkaProducer.java:295)
	at reactor.kafka.sender.internals.ProducerFactory.createProducer(ProducerFactory.java:34)
	at reactor.kafka.sender.internals.DefaultKafkaSender.lambda$new$2(DefaultKafkaSender.java:102)
	at reactor.core.publisher.MonoCallable.call(MonoCallable.java:72)
	at reactor.core.publisher.FluxSubscribeOnCallable$CallableSubscribeOnSubscription.run(FluxSubscribeOnCallable.java:228)
	at reactor.core.scheduler.ImmediateScheduler.schedule(ImmediateScheduler.java:52)
	at reactor.core.publisher.MonoSubscribeOnCallable.subscribe(MonoSubscribeOnCallable.java:52)
	at reactor.core.publisher.MonoCacheTime.subscribeOrReturn(MonoCacheTime.java:143)
	at reactor.core.publisher.Flux.subscribe(Flux.java:8876)
	at reactor.core.publisher.Flux.subscribeWith(Flux.java:9012)
	at reactor.core.publisher.Flux.subscribe(Flux.java:8856)
	at reactor.core.publisher.Flux.subscribe(Flux.java:8780)
	at reactor.core.publisher.Flux.subscribe(Flux.java:8698)
	at com.Service.run(Service.java:53)
	at org.springframework.boot.SpringApplication.lambda$callRunner$5(SpringApplication.java:788)
	at org.springframework.util.function.ThrowingConsumer$1.acceptWithException(ThrowingConsumer.java:82)
	at org.springframework.util.function.ThrowingConsumer.accept(ThrowingConsumer.java:60)
	at org.springframework.util.function.ThrowingConsumer$1.accept(ThrowingConsumer.java:86)
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:796)
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:787)
	at org.springframework.boot.SpringApplication.lambda$callRunners$3(SpringApplication.java:772)
	at java.base@24/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:186)
	at java.base@24/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357)
	at java.base@24/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:571)
	at java.base@24/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:560)
	at java.base@24/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:153)
	at java.base@24/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:176)
	at java.base@24/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:265)
	at java.base@24/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:636)
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:772)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:325)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350)
	at com.Application.main(Application.java:18)
	at java.base@24/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)

Wondering what did I do wrong. I did not apply (just bump the version and built a native image)

<plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <image>
                        <env>
                            <BP_JVM_VERSION>24</BP_JVM_VERSION>
                            <BP_NATIVE_IMAGE>TRUE</BP_NATIVE_IMAGE>
                        </env>
                        <buildpacks>
                            <buildpack>paketobuildpacks/java-native-image:11.9.0</buildpack>
                        </buildpacks>
                    </image>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
            </plugin>

To add more details, GraalVM24. 3.4.4 NON native image will work fine.

Once it is native image GraalVm24 + 3.4.4, exception is reproducible

@mhalbritter
Copy link
Contributor Author

Yeah, that fix is in 3.4.4.

I just looked at your sample and you're using reactor-kafka. The fix I applied was to register the runtime hints on KafkaAutoConfiguration, which doesn't apply to your case. Spring Boot has no auto-configuration for reactor-kafka, so you have to apply the workaround yourself.

@patpatpat123
Copy link

I see. Understood. Many thanks

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

2 participants