{"record":{"id":"de363f70a1bf83e1","repo":"quarkusio/quarkus","slug":"unsupported-aot-cache-version-expected-version","errorCode":null,"errorMessage":"Unsupported AOT cache version: expected ${VERSION} but got ${version}","messagePattern":"Unsupported AOT cache version: expected (.+?) but got (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"critical","filePath":"independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/AotSerializedApplication.java","lineNumber":164,"sourceCode":"\n    /**\n     * Reads cached resources from an input stream.\n     *\n     * @param in the input stream to read from\n     * @return an AotSerializedApplication containing the main class and cached resources\n     * @throws IOException if an I/O error occurs or the format is invalid\n     */\n    public static AotSerializedApplication read(InputStream in) throws IOException {\n        try (DataInputStream data = new DataInputStream(in)) {\n            int magic = data.readInt();\n            if (magic != MAGIC) {\n                throw new IOException(\"Invalid magic number in AOT cache file: expected 0x\"\n                        + Integer.toHexString(MAGIC) + \" but got 0x\" + Integer.toHexString(magic));\n            }\n\n            int version = data.readInt();\n            if (version != VERSION) {\n                throw new IOException(\"Unsupported AOT cache version: expected \" + VERSION + \" but got \" + version);\n            }\n\n            String mainClass = data.readUTF();\n\n            // Read tracked directories\n            int fullyIndexedDirectoryCount = data.readInt();\n            Set<String> fullyIndexedDirectories = new HashSet<>((int) Math.ceil(fullyIndexedDirectoryCount / 0.75f));\n            for (int i = 0; i < fullyIndexedDirectoryCount; i++) {\n                fullyIndexedDirectories.add(data.readUTF());\n            }\n\n            // Read directory contents\n            int fullyIndexedResourceCount = data.readInt();\n            Set<String> fullyIndexedResources = new HashSet<>((int) Math.ceil(fullyIndexedResourceCount / 0.75f));\n            for (int i = 0; i < fullyIndexedResourceCount; i++) {\n                fullyIndexedResources.add(data.readUTF());\n            }\n","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/AotSerializedApplication.java#L146-L182","documentation":"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.","triggerScenarios":"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).","commonSituations":"Upgrading Quarkus but reusing a previously built quarkus-app directory or Docker layer cache; mixing runner and app artifacts from different builds.","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."],"exampleFix":"// before: reusing old build dir after Quarkus upgrade\njava -jar target/quarkus-app/quarkus-run.jar // stale cache\n\n// after\nmvn clean package && java -jar target/quarkus-app/quarkus-run.jar","handlingStrategy":"fallback","validationCode":"Path cache = Paths.get(\"target/quarkus-app/quarkus-application.dat\");\nlong lastBuilt = Files.getLastModifiedTime(cache).toMillis();\nlong runnerBuilt = Files.getLastModifiedTime(Paths.get(\"target/quarkus-app/quarkus-run.jar\")).toMillis();\nif (Math.abs(lastBuilt - runnerBuilt) > 60_000) {\n    System.err.println(\"WARNING: cache and runner timestamps differ; rebuild required\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    app = AotSerializedApplication.read(in);\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Unsupported AOT cache version\")) {\n        throw new IllegalStateException(\"Cache built by different Quarkus version; run mvn clean package\", e);\n    } throw e;\n}","preventionTips":["Always rebuild after upgrading Quarkus.","Purge Docker/CI caches keyed to old Quarkus versions.","Keep runner jar and cache artifacts from the same build."],"tags":["aot","version-mismatch","serialization","startup"],"backgroundTag":"version-mismatch","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}