jwtk/jjwt · critical · UnknownClassException
Unable to load class named [${fqcn}] from the thread context
Error message
Unable to load class named [${fqcn}] from the thread context, current, or system/application ClassLoaders. All heuristics have been exhausted. Class could not be found.${implHint} What it means
UnknownClassException thrown by io.jsonwebtoken.lang.Classes.forName when the named class cannot be loaded from the thread context, current, or system/application classloaders after all lookup heuristics fail. jjwt uses reflection to locate its default implementation classes, so this typically means the required jjwt module jar is absent from the runtime classpath.
Source
Thrown at api/src/main/java/io/jsonwebtoken/lang/Classes.java:90
Class<?> clazz = THREAD_CL_ACCESSOR.loadClass(fqcn);
if (clazz == null) {
clazz = CLASS_CL_ACCESSOR.loadClass(fqcn);
}
if (clazz == null) {
clazz = SYSTEM_CL_ACCESSOR.loadClass(fqcn);
}
if (clazz == null) {
String msg = "Unable to load class named [" + fqcn + "] from the thread context, current, or " +
"system/application ClassLoaders. All heuristics have been exhausted. Class could not be found.";
if (fqcn != null && fqcn.startsWith("io.jsonwebtoken.impl")) {
msg += " Have you remembered to include the jjwt-impl.jar in your runtime classpath?";
}
throw new UnknownClassException(msg);
}
return (Class<T>) clazz;
}
/**
* Returns the specified resource by checking the current thread's
* {@link Thread#getContextClassLoader() context class loader}, then the
* current ClassLoader (<code>Classes.class.getClassLoader()</code>), then the system/application
* ClassLoader (<code>ClassLoader.getSystemClassLoader()</code>, in that order, using
* {@link ClassLoader#getResourceAsStream(String) getResourceAsStream(name)}.
*
* @param name the name of the resource to acquire from the classloader(s).
* @return the InputStream of the resource found, or <code>null</code> if the resource cannot be found from any
* of the three mentioned ClassLoaders.
* @since 0.8
*/
public static InputStream getResourceAsStream(String name) {View on GitHub (pinned to fb71496164)
Solutions
- Add jjwt-impl and a serializer module (jjwt-jackson or jjwt-gson) to the runtime classpath, e.g. io.jsonwebtoken:jjwt-impl:<same-version> and io.jsonwebtoken:jjwt-jackson:<same-version>
- Verify the jjwt-impl jar version matches the jjwt-api version exactly
- Check that the thread context classloader can see the jar (app servers/OSGi); set Thread.currentThread().setContextClassLoader(...) or declare the dependency in the right module
- Confirm the fully qualified class name passed to Classes.forName is spelled correctly
Example fix
// before (Maven) <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> // after <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency>
Defensive patterns
Strategy: fallback
Validate before calling
if (!Classes.isAvailable("io.jsonwebtoken.impl.DefaultJwtBuilder")) {
throw new IllegalStateException("jjwt-impl (and a JSON serializer module) missing from runtime classpath");
} Try / catch
try {
return Jwts.parserBuilder().build();
} catch (UnknownClassException e) {
throw new IllegalStateException("Add jjwt-impl and jjwt-jackson to the runtime classpath", e);
} Prevention
- Always declare jjwt-impl plus jjwt-jackson or jjwt-gson alongside jjwt-api at the same version
- Use scope runtime for impl so compile-time API usage cannot silently bypass it
- Run a startup smoke test that builds a parser to fail fast on missing jars
When it happens
Trigger: Calling any jjwt API that resolves an implementation class by name (Classes.forName, and transitively isAvailable/newInstance) while the class's jar is not on the classpath. The message gains the jjwt-impl.jar hint when the fqcn starts with io.jsonwebtoken.impl.
Common situations: Declaring only jjwt-api as a dependency without jjwt-impl (and jjwt-jackson/gson); runtime classpath assembled manually without the impl jar; shaded/multi-classloader environments (app servers, OSGi, Android) where the thread context classloader differs.
Related errors
- Unable to invoke class method ${fqcn}#${methodName}. Ensure
- Unable to invoke class method ${clazzName}#${methodName}. En
- Unable to find an implementation for ${spi} using java.util.
- Unexpected unsecured Claims JWT.
- Unexpected content JWS.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/25268b90be84cf83.
Report an issue: GitHub.