AF5 migration: Issue reading ConfigToken from Postgres

Hi
I am migrating my AF4 apps to AF5 (version 5.1.1, AxonServer 2026.x).
My expectation is that I can migrate to AF5 using existing AxonServer eventstores and existing projections in Postgres (and Clickhouse).

In AF5 the package of class ConfigToken changed and I get startup errors when using an AF4-database.

With an AF4 app, the __config row in tokenentry table looks like this:

__config,0,,2026-06-02T15:24:55.193Z,org.axonframework.eventhandling.tokenstore.ConfigToken,"{""config"":[""java.util.Collections$SingletonMap"",{""id"":""65e451eb-28db-4f7b-9672-6ea76311b319""}]}"

In an AF5 app the row looks like this:

__config,0,,2026-06-02T15:28:56.723Z,org.axonframework.messaging.eventhandling.processing.streaming.token.store.ConfigToken,"{""config"":{""id"":""e135cbbb-30e8-431d-9564-846a3b099950""}}",0

When starting an AF5 app using the database with tokenentry table created with AF4, the app fails to start with the following error:

2026-06-02 17:26:56 ERROR [                          main] o.s.boot.SpringApplication                         : Application run failed
org.springframework.context.ApplicationContextException: Failed to start bean 'axon-start-lifecycle-handler-3'
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:423)

<snip>

Caused by: org.axonframework.messaging.eventhandling.processing.streaming.token.store.UnableToRetrieveIdentifierException: Exception occurred while trying to retrieve storage identifier
at org.axonframework.messaging.eventhandling.processing.streaming.token.store.jpa.JpaTokenStore.lambda$retrieveStorageIdentifier$12(JpaTokenStore.java:442)
at org.axonframework.common.jpa.EntityManagerExecutor.apply(EntityManagerExecutor.java:50)
at org.axonframework.messaging.eventhandling.processing.streaming.token.store.jpa.JpaTokenStore.retrieveStorageIdentifier(JpaTokenStore.java:438)
at org.axonframework.messaging.core.unitofwork.UnitOfWork.lambda$executeWithResult$0(UnitOfWork.java:162)
at org.axonframework.messaging.core.unitofwork.UnitOfWork.safe(UnitOfWork.java:177)
at org.axonframework.messaging.core.unitofwork.UnitOfWork.lambda$executeWithResult$1(UnitOfWork.java:162)
at org.axonframework.messaging.core.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.lambda$safe$2(UnitOfWork.java:274)
at org.axonframework.messaging.core.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.lambda$runNextPhase$8(UnitOfWork.java:427)
at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire$$$capture(CompletableFuture.java:1150)
at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java)
at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:482)
at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1184)
at java.base/java.util.concurrent.CompletableFuture.thenComposeAsync(CompletableFuture.java:2352)
at org.axonframework.messaging.core.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.lambda$runNextPhase$9(UnitOfWork.java:427)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.concurrent.ConcurrentLinkedQueue.forEachFrom(ConcurrentLinkedQueue.java:1037)
at java.base/java.util.concurrent.ConcurrentLinkedQueue$CLQSpliterator.forEachRemaining(ConcurrentLinkedQueue.java:894)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:662)
at org.axonframework.messaging.core.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.runNextPhase(UnitOfWork.java:430)
at org.axonframework.messaging.core.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.executeAllPhaseHandlers(UnitOfWork.java:376)
at org.axonframework.messaging.core.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.commit(UnitOfWork.java:349)
at org.axonframework.messaging.core.unitofwork.UnitOfWork.execute(UnitOfWork.java:142)
at org.axonframework.messaging.core.unitofwork.UnitOfWork.executeWithResult(UnitOfWork.java:164)
at org.axonframework.messaging.eventhandling.processing.streaming.pooled.PooledStreamingEventProcessor.calculateIdentifier(PooledStreamingEventProcessor.java:213)
at org.axonframework.messaging.eventhandling.processing.streaming.pooled.PooledStreamingEventProcessor.lambda$getTokenStoreIdentifier$1(PooledStreamingEventProcessor.java:208)
at java.base/java.util.concurrent.atomic.AtomicReference.updateAndGet(AtomicReference.java:210)
at org.axonframework.messaging.eventhandling.processing.streaming.pooled.PooledStreamingEventProcessor.getTokenStoreIdentifier(PooledStreamingEventProcessor.java:208)
at io.axoniq.framework.axonserver.connector.event.EventProcessorInfoUtils.describeStreaming(EventProcessorInfoUtils.java:63)
at io.axoniq.framework.axonserver.connector.event.EventProcessorControlService.lambda$infoSupplier$1(EventProcessorControlService.java:128)
at io.axoniq.axonserver.connector.impl.ControlChannelImpl.lambda$sendScheduledProcessorInfo$7(ControlChannelImpl.java:308)
at java.base/java.util.concurrent.ConcurrentHashMap$ValuesView.forEach(ConcurrentHashMap.java:4783)
at io.axoniq.axonserver.connector.impl.ControlChannelImpl.sendScheduledProcessorInfo(ControlChannelImpl.java:308)
at io.axoniq.axonserver.connector.impl.ControlChannelImpl.registerEventProcessor(ControlChannelImpl.java:289)
at io.axoniq.framework.axonserver.connector.event.EventProcessorControlService.lambda$registerInstructionHandlers$0(EventProcessorControlService.java:121)
at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:986)
at java.base/java.util.Collections$UnmodifiableMap.forEach(Collections.java:1708)
at io.axoniq.framework.axonserver.connector.event.EventProcessorControlService.registerInstructionHandlers(EventProcessorControlService.java:121)
at io.axoniq.framework.axonserver.connector.event.EventProcessorControlService.start(EventProcessorControlService.java:114)
at org.axonframework.common.configuration.ComponentDefinition.lambda$onStart$0(ComponentDefinition.java:181)
at org.axonframework.common.configuration.AbstractComponent.lambda$initLifecycle$0(AbstractComponent.java:133)
at org.axonframework.common.configuration.LifecycleRegistry.lambda$onStart$1(LifecycleRegistry.java:110)
at org.axonframework.extension.spring.config.SpringLifecycleRegistry.lambda$onStart$0(SpringLifecycleRegistry.java:71)
at org.axonframework.extension.spring.config.SpringLifecycleStartHandler.start(SpringLifecycleStartHandler.java:60)
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:420)
... 14 common frames omitted
Caused by: java.lang.RuntimeException: Could not load class org.axonframework.eventhandling.tokenstore.ConfigToken
at org.axonframework.common.ClassUtils.lambda$loadClass$0(ClassUtils.java:49)
at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
at org.axonframework.common.ClassUtils.loadClass(ClassUtils.java:45)
at org.axonframework.messaging.eventhandling.processing.streaming.token.store.jpa.TokenEntry.getToken(TokenEntry.java:124)
at org.axonframework.messaging.eventhandling.processing.streaming.token.store.jpa.JpaTokenStore.getConfig(JpaTokenStore.java:462)
at org.axonframework.messaging.eventhandling.processing.streaming.token.store.jpa.JpaTokenStore.lambda$retrieveStorageIdentifier$12(JpaTokenStore.java:440)
... 61 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.axonframework.eventhandling.tokenstore.ConfigToken
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
at org.axonframework.common.ClassUtils.lambda$loadClass$0(ClassUtils.java:47)
... 66 common frames omitted

I did not find anything in the migration docs regarding the TokenEntry table.

Is there a migration step for this? Or is it a bug?

Thanks
Klaus

Hi Klaus,

not a bug, but probably an oversight. We will have a look.
If you’re not running AF4 and AF5 concurrently on the same processing group (which is not a recommended thing to do anyway), you can update the token type row to “org.axonframework.messaging.eventhandling.processing.streaming.token.store.ConfigToken”. This merely used for deserialization of the right type of token.

The GlobalIndexTrackingToken has also been moved to another package. It is now in “org.axonframework.messaging.eventhandling.processing.streaming.token.GlobalSequenceTrackingToken”. You may require to update the other columns as well.

Meanwhile, I’ll put an issue on the board of the Framework team to address this conversion in the framework itself.

Hello Allard,
it’s okay if we have a downtime once when migrating an app/database to AF5, so there should not be AF4 and AF5 apps active in parallel.

In our system we manage the Axon database tables using Flyway, so we usually create migration scripts if some Aon tables are added or changed.
In the meantime I managed to create a Flyway migration script for Postgres. Maybe helpful for others:

UPDATE tokenentry
SET
  tokentype = CASE
                WHEN processorname = '__config'
                  THEN 'org.axonframework.messaging.eventhandling.processing.streaming.token.store.ConfigToken'
                ELSE REPLACE(
                  tokentype,
                  'org.axonframework.eventhandling.',
                  'org.axonframework.messaging.eventhandling.processing.streaming.token.'
               )
    END,
  token = CASE
            WHEN processorname = '__config'
              THEN convert_to(
              '{"config":{"id":"' ||
              (SELECT convert_from(token, 'UTF8')::json->'config'->1->>'id'
                FROM tokenentry
                WHERE processorname = '__config') ||
                        '"}}',
                        'UTF8'
                         )
            ELSE token
    END,
  owner = CASE
            WHEN processorname = '__config' THEN NULL
            ELSE owner
    END
WHERE
  processorname = '__config'
   OR tokentype LIKE 'org.axonframework.eventhandling.%';