quarkusio/quarkus · error · RuntimeException
Wrong class path version
Error message
Wrong class path version
What it means
SerializedApplication.read deserializes the fast-jar application manifest that Quarkus generated at build time. After checking the magic number, it verifies the serialized class path VERSION constant; if the stream's version differs from the reader's expected VERSION, it throws 'Wrong class path version'. This protects against running an app root produced by an incompatible Quarkus build.
Solutions
- Rebuild the whole application with the same Quarkus version used by the runner (mvn clean package or gradle clean build)
- Ensure the quarkus-run.jar / bootstrap runner version matches the version that produced the app artifacts — do not mix runner jars across Quarkus releases
- Delete stale target/ or build/ directories and regenerate the fast-jar output
- If reading programmatically, use a SerializedApplication reader from the same Quarkus version that built the application
Example fix
// before: mixing runner and app from different versions java -jar old-quarkus-run/quarkus-run.jar -jarg new-app/quarkus-application.dat // after: regenerate both from one build ./mvnw clean package && java -jar target/quarkus-app/quarkus-run.jar
Defensive patterns
Strategy: try-catch
Validate before calling
// Java: pre-check the serialized app version before reading fully
try (DataInputStream in = new DataInputStream(Files.newInputStream(appFile))) {
int magic = in.readInt();
int version = in.readInt();
if (magic != MAGIC || version != EXPECTED_VERSION) {
throw new IllegalStateException("App built with incompatible Quarkus version (version=" + version + "); rebuild required");
}
} Type guard
static boolean isCompatibleVersion(int version) { return version == VERSION; } Try / catch
try {
SerializedApplication app = SerializedApplication.read(in, appRoot);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().contains("Wrong class path version")) {
throw new IllegalStateException("Runner and application Quarkus versions differ; run a clean rebuild", e);
}
throw e;
} Prevention
- Always launch the app with the quarkus-run.jar produced by the same build as the fast-jar artifacts
- Run clean builds after upgrading Quarkus; never mix target/ outputs across versions
- Pin the Quarkus BOM version so runner and application modules stay in sync
- Add a startup smoke test in CI that boots the packaged jar after each build
When it happens
Trigger: Calling SerializedApplication.read(InputStream, Path) on an io.quarkus.app-files (serialized application) file whose embedded int version does not equal the VERSION constant compiled into the reader — typically when the app-cd/binaries were built by a different Quarkus version than the one loading them.
Common situations: Mixed-version deployments: rebuilding only part of an application with a newer Quarkus, copying an old quarkus-run.jar against a new application artifact (or vice versa), or stale build output in target/ after a Quarkus upgrade.
Related errors
- Unsupported AOT cache version: expected
- A skip predicate instance cannot be scheduled…
- A skipPredicate instance may not be serialized
- A task instance cannot be scheduled programmatically if DB…
- An async task instance cannot be scheduled programmatically…
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/02aac8e107d79537.
Report an issue: GitHub.
Appendix: source
Thrown at independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/runner/SerializedApplication.java:138
data.writeShort(fullyIndexedResourcesToCPJarIndex.size());
for (Map.Entry<String, List<Integer>> entry : fullyIndexedResourcesToCPJarIndex.entrySet()) {
data.writeUTF(entry.getKey());
data.writeShort(entry.getValue().size());
for (Integer index : entry.getValue()) {
data.writeShort(index);
}
}
data.flush();
}
}
public static SerializedApplication read(InputStream inputStream, Path appRoot) throws IOException {
try (DataInputStream in = new DataInputStream(inputStream)) {
if (in.readInt() != MAGIC) {
throw new RuntimeException("Wrong magic number");
}
if (in.readInt() != VERSION) {
throw new RuntimeException("Wrong class path version");
}
String mainClass = in.readUTF();
ResourceDirectoryTracker resourceDirectoryTracker = new ResourceDirectoryTracker();
int numPaths = in.readUnsignedShort();
ClassLoadingResource[] allClassLoadingResources = new ClassLoadingResource[numPaths];
ClassLoadingResource generatedBytecodeClassLoadingResource = null;
Set<String> generatedBytecode = Set.of();
ClassLoadingResource transformedBytecodeClassLoadingResource = null;
Set<String> transformedBytecode = Set.of();
for (int pathCount = 0; pathCount < numPaths; pathCount++) {
String path = in.readUTF();
boolean hasManifest = in.readBoolean();
ManifestInfo info = null;
if (hasManifest) {
info = new ManifestInfo(readNullableString(in), readNullableString(in), readNullableString(in),
readNullableString(in), readNullableString(in), readNullableString(in));
}
JarResource resource = new JarResource(info, appRoot.resolve(path));View on GitHub (pinned to e1c734241f)