quarkusio/quarkus · critical · IOException

Unsupported AOT cache version: expected

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.

Solutions

  1. Rebuild the application (mvn clean package) so the cache version matches the runner version.
  2. Clear stale Docker/CI layer caches so the old quarkus-application.dat is not reused.
  3. 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

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


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/de363f70a1bf83e1. Report an issue: GitHub.

Appendix: 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)