AF5 query handlers cannot be called from AF4 app

Hi
it seems that Axon 5 apps are not communication-compatible with Axon 4 apps.
I tried running one app migrated to AF5 and others still running AF4. Queries sent via AxonServer from the AF4 get errors The given version is unsupported because it is empty on the QueryHandling AF5 side:

2026-06-30 13:09:58  WARN [       grpc-default-executor-4] i.a.a.c.query.impl.QueryChannelImpl                : Error on QueryChannel for context default   
io.grpc.StatusRuntimeException: CANCELLED: Failed to read message.
	at io.grpc.Status.asRuntimeException(Status.java:532)
	at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:581)
	at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
	at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
	at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:566)
	at io.grpc.internal.ClientCallImpl.access$100(ClientCallImpl.java:72)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:734)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:715)
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.IllegalArgumentException: The given version is unsupported because it is empty.
	at org.axonframework.messaging.core.MessageType.lambda$new$0(MessageType.java:64)
	at org.axonframework.common.Assert.assertThat(Assert.java:117)
	at org.axonframework.messaging.core.MessageType.<init>(MessageType.java:61)
	at org.axonframework.messaging.core.MessageType.<init>(MessageType.java:101)
	at io.axoniq.framework.axonserver.connector.query.QueryConverter.convertQueryRequest(QueryConverter.java:85)
	at io.axoniq.framework.axonserver.connector.query.AxonServerQueryBusConnector$LocalSegmentAdapter.stream(AxonServerQueryBusConnector.java:252)
	at io.axoniq.axonserver.connector.query.impl.QueryChannelImpl.executeQuery(QueryChannelImpl.java:574)
	at io.axoniq.axonserver.connector.query.impl.QueryChannelImpl.lambda$doHandleQuery$25(QueryChannelImpl.java:546)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:1024)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)

I did not try commands yet, maybe there will be the same issue because AF4 commands could be simple plain classes without a version.

Did I miss something? Do we need some compatibility setting?
Otherwise, this is definitely a showstopper in my opinion.

Mabe it related to Unable to read AF4 events in AF5 due to revision non-null requirement · Issue #4625 · AxonIQ/AxonFramework · GitHub that I posted recently?

Klaus

Klaus

Hi Klaus,

having a quick look on the code in the AxonServerQueryBusConnector / QueryConverter and AxonServerCommandBusConnector / CommandConverter this indeed looks like a similar problem, but less obvious because commands/queries are transient and short-lived and the problem only surfaces if - as you explained - messages are sent from AF4 to AF5 applications.

Thanks for reporting that, I’ve recorded it as a bug for Axon Framework - feel free to edit it or add any additional information as needed, we’ll prioritize it accordingly and include it in one of our next releases.

One more thing, the workaround might be easier here: I did not check it, but it might be possible to just annotate the AF4 message payloads with @Revision. Since commands/queries are not persisted, this should be enough to make them carry a revision at runtime.

However, it might not always be an option to do that, so we’ll look into an alternative fix anyhow.