apache/beam · error · RuntimeException
Cannot detect classpath: classload is null (is it the…
Error message
Cannot detect classpath: classload is null (is it the bootstrap classloader?)
What it means
When lazily creating the shared Kryo instance, KryoState reads the current thread's context ClassLoader to scope Kryo's classpath/class resolution. If the context ClassLoader is null (typically only the bootstrap ClassLoader situation), it throws a RuntimeException because Kryo could not resolve application classes. This is an environment/threading problem, not a data problem.
Solutions
- Set the context ClassLoader on the thread before decoding: Thread.currentThread().setContextClassLoader(AppClass.class.getClassLoader()).
- Configure the runner/worker environment so application threads have a proper context classloader.
- If spawning your own threads, pass and set the classloader from the creating thread.
- Avoid relying on the bootstrap classloader; ensure code runs on a worker classloader containing user code.
Example fix
// before: custom thread without classloader new Thread(() -> pipeline.run()).start(); // after Thread t = new Thread(() -> pipeline.run()); t.setContextClassLoader(MyPipeline.class.getClassLoader()); t.start();
Defensive patterns
Strategy: validation
Validate before calling
if (Thread.currentThread().getContextClassLoader() == null) { Thread.currentThread().setContextClassLoader(MyClass.class.getClassLoader()); } Prevention
- Never leave worker threads without a context ClassLoader
- Set the classloader explicitly in custom thread pools and runners
- Ensure user code runs on a worker classloader, not the bootstrap one
When it happens
Trigger: KryoState.getOrCreate executing on a thread whose context ClassLoader was never set or was explicitly cleared (null), e.g. certain runner/system threads or threads created before classloader configuration.
Common situations: Running on a runner or container whose worker threads lack a context classloader; using Kryo coder inside custom thread pools where Thread.currentThread().setContextClassLoader was never called; bootstrap-classloader-only environments.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- CalcFn failed to evaluate
- Cannot decode object from input stream.
- Cannot encode a null value.
- Cannot encode given object of type [<value.getClass()>].
- Cannot provide [ ], given type descriptor's [ ] raw type is…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/96bb613b9325d596.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/extensions/kryo/src/main/java/org/apache/beam/sdk/extensions/kryo/KryoState.java:66
private final ThreadLocal<Map<String, KryoState>> kryoStateMap =
ThreadLocal.withInitial(HashMap::new);
KryoState getOrCreate(KryoCoder<?> coder) {
return kryoStateMap
.get()
.computeIfAbsent(
coder.getInstanceId(),
k -> {
final Kryo kryo = new Kryo();
// fallback in case serialized class does not have default constructor
kryo.setInstantiatorStrategy(
new DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));
kryo.setReferences(coder.getOptions().getReferences());
kryo.setRegistrationRequired(coder.getOptions().getRegistrationRequired());
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
throw new RuntimeException(
"Cannot detect classpath: classload is null (is it the bootstrap classloader?)");
}
kryo.setClassLoader(classLoader);
// first id of user provided class registration
final int firstRegistrationId = kryo.getNextRegistrationId();
// register user provided classes
for (KryoRegistrar registrar : coder.getRegistrars()) {
registrar.registerClasses(kryo);
}
return new KryoState(
kryo,
firstRegistrationId,
new InputChunked(coder.getOptions().getBufferSize()),
new OutputChunked(coder.getOptions().getBufferSize()));
});
}
}View on GitHub (pinned to 12126d8942)