quarkusio/quarkus · critical · IOException
Unsupported AOT cache version: expected ${VERSION} but got $
Error message
Unsupported AOT cache version: expected ${VERSION} but got ${version} What it means
After the magic check, AotSerializedApplication.read() reads a version integer that must match the VERSION constant of the running runner. A mismatch means the cache was produced by a different Quarkus version than the one reading it, so the binary layout cannot be trusted and an IOException is thrown with both version numbers.
Source
Thrown at independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/AotSerializedApplication.java:164
/**
* Reads cached resources from an input stream.
*
* @param in the input stream to read from
* @return an AotSerializedApplication containing the main class and cached resources
* @throws IOException if an I/O error occurs or the format is invalid
*/
public static AotSerializedApplication read(InputStream in) throws IOException {
try (DataInputStream data = new DataInputStream(in)) {
int magic = data.readInt();
if (magic != MAGIC) {
throw new IOException("Invalid magic number in AOT cache file: expected 0x"
+ Integer.toHexString(MAGIC) + " but got 0x" + Integer.toHexString(magic));
}
int version = data.readInt();
if (version != VERSION) {
throw new IOException("Unsupported AOT cache version: expected " + VERSION + " but got " + version);
}
String mainClass = data.readUTF();
// Read tracked directories
int fullyIndexedDirectoryCount = data.readInt();
Set<String> fullyIndexedDirectories = new HashSet<>((int) Math.ceil(fullyIndexedDirectoryCount / 0.75f));
for (int i = 0; i < fullyIndexedDirectoryCount; i++) {
fullyIndexedDirectories.add(data.readUTF());
}
// Read directory contents
int fullyIndexedResourceCount = data.readInt();
Set<String> fullyIndexedResources = new HashSet<>((int) Math.ceil(fullyIndexedResourceCount / 0.75f));
for (int i = 0; i < fullyIndexedResourceCount; i++) {
fullyIndexedResources.add(data.readUTF());
}
View on GitHub (pinned to e1c734241f)
Solutions
- Rebuild the application (mvn clean package) so the cache version matches the runner version.
- Clear stale Docker/CI layer caches so the old quarkus-application.dat is not reused.
- Ensure the runner jar and the cache come from the same Quarkus version.
Example fix
// before: reusing old build dir after Quarkus upgrade java -jar target/quarkus-app/quarkus-run.jar // stale cache // after mvn clean package && java -jar target/quarkus-app/quarkus-run.jar
Defensive patterns
Strategy: fallback
Validate before calling
Path cache = Paths.get("target/quarkus-app/quarkus-application.dat");
long lastBuilt = Files.getLastModifiedTime(cache).toMillis();
long runnerBuilt = Files.getLastModifiedTime(Paths.get("target/quarkus-app/quarkus-run.jar")).toMillis();
if (Math.abs(lastBuilt - runnerBuilt) > 60_000) {
System.err.println("WARNING: cache and runner timestamps differ; rebuild required");
} Try / catch
try {
app = AotSerializedApplication.read(in);
} catch (IOException e) {
if (e.getMessage().startsWith("Unsupported AOT cache version")) {
throw new IllegalStateException("Cache built by different Quarkus version; run mvn clean package", e);
} throw e;
} Prevention
- Always rebuild after upgrading Quarkus.
- Purge Docker/CI caches keyed to old Quarkus versions.
- Keep runner jar and cache artifacts from the same build.
When it happens
Trigger: Reading a quarkus-application.dat generated by a different Quarkus version than the AotSerializedApplication class performing the read (upgraded runner jar with old cache, or downgraded runner with newer cache).
Common situations: Upgrading Quarkus but reusing a previously built quarkus-app directory or Docker layer cache; mixing runner and app artifacts from different builds.
Related errors
- Invalid magic number in AOT cache file: expected 0x${MAGIC}
- Unable to determine launch jar path
- Serialized application file not found or not readable: ${cac
- Wrong class path version
- ${misalignmentReport}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/de363f70a1bf83e1.
Report an issue: GitHub.