gradle/gradle · error · RuntimeException
Cannot load worker action's class
Error message
Cannot load worker action's class
What it means
Worker actions are shipped to the child JVM as serialized objects and read back with a ClassLoaderObjectInputStream bound to the worker's classloader. ClassNotFoundException during readObject is rethrown as this RuntimeException: the action's class, or a type it references, is absent from the classloader the worker process was configured with. The cause names the missing class.
Source
Thrown at platforms/core-execution/worker-main/src/main/java/org/gradle/process/internal/worker/messaging/WorkerConfigSerializer.java:93
encoder.writeSmallInt(config.getNativeServicesMode().ordinal());
encoder.writeString(config.getGradleUserHomeDirPath());
new MultiChoiceAddressSerializer().write(encoder, config.getServerAddress());
encoder.writeSmallLong(config.getWorkerId());
encoder.writeString(config.getDisplayName());
encoder.writeBinary(serializeWorker(config.getWorkerAction()));
}
private static Action<? super WorkerProcessContext> deserializeWorker(byte[] serializedWorker, ClassLoader loader) throws IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(serializedWorker);
ObjectInputStream in = null;
try {
in = new ClassLoaderObjectInputStream(bais, loader);
@SuppressWarnings("unchecked")
Action<? super WorkerProcessContext> workerAction = (Action<? super WorkerProcessContext>) in.readObject();
return workerAction;
} catch (ClassNotFoundException e) {
throw new RuntimeException("Cannot load worker action's class", e);
} catch (UnsupportedClassVersionError e) {
String message;
if (e instanceof UnsupportedClassVersionErrorWithJavaVersion) {
UnsupportedClassVersionErrorWithJavaVersion e2 = (UnsupportedClassVersionErrorWithJavaVersion) e;
message = String.format(
"Unsupported worker JDK version. Required: %s. Current: %s",
e2.getVersion().getMajorVersion(), JavaVersion.current().getMajorVersion()
);
} else {
message = "Unsupported worker JDK version: " + JavaVersion.current().getMajorVersion();
}
throw new GradleException(message, e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
LOGGER.debug("Error closing ObjectInputStream", e);View on GitHub (pinned to 534f27719b)
Solutions
- Read the cause to get the missing class name, then locate which jar should provide it
- Add that jar to the worker's implementation classpath (setImplementationClasspath / workerImplementation)
- Rebuild and republish plugin jars so both sides of the worker boundary match
- Do not shade or relocate classes that cross the process boundary
Example fix
// before builder.setImplementationClasspath(Arrays.asList(gradleApiJar)); // action class com.acme.MyWorkerAction lives in acme-worker.jar -> ClassNotFoundException // after builder.setImplementationClasspath(Arrays.asList(gradleApiJar, acmeWorkerJar));
Defensive patterns
Strategy: validation
Validate before calling
try {
Class.forName("com.acme.MyWorkerAction", false, workerClassLoader);
} catch (ClassNotFoundException e) {
// add the missing jar to the worker implementation classpath before starting
throw new IllegalStateException("Worker action class missing from worker classpath", e);
} Try / catch
try {
action = deserializeWorker(bytes, loader);
} catch (RuntimeException e) {
if (e.getCause() instanceof ClassNotFoundException) {
// named class is absent: fix the implementation classpath, do not retry blindly
} else {
throw e;
}
} Prevention
- Derive the worker classpath from the same jars that built the serialized action
- Do not shade or relocate classes that cross the worker boundary
- Rebuild both sides together when plugin jars change
When it happens
Trigger: Deserializing the worker action in the child when the classpath given to the worker process (implementation classpath) does not include every jar holding the action and the types it references.
Common situations: Custom worker process implementations with incomplete classpath entries, stale or republished plugin jars after an upgrade, shaded/relocated classes crossing the worker boundary, version drift between serializer and worker classloader.
Related errors
- Could not initialise system classpath.
- Illegal null value provided in this collection: %s
- Could not determine classpath for {}
- Could not write cache value to '%s'.
- Could not read cache value from '%s'.
AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22).
Data as JSON: /api/errors/20e4d40a6843cb00.
Report an issue: GitHub.