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

  1. Read the cause to get the missing class name, then locate which jar should provide it
  2. Add that jar to the worker's implementation classpath (setImplementationClasspath / workerImplementation)
  3. Rebuild and republish plugin jars so both sides of the worker boundary match
  4. 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

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


AI-assisted analysis of gradle/gradle@534f27719b (2026-08-22). Data as JSON: /api/errors/20e4d40a6843cb00. Report an issue: GitHub.