jwtk/jjwt · error · IllegalArgumentException
${message}Object of class [${objClassName}] must be an insta
Error message
${message}Object of class [${objClassName}] must be an instance of ${type} What it means
Thrown by Assert.isInstanceOf(Class, Object, String) when the object is not an instance of the required type. The message concatenates the caller's prefix plus 'Object of class [X] must be an instance of Y'. JJWT uses this to enforce internal type contracts (e.g. expected key or provider types), surfacing as IllegalArgumentException.
Source
Thrown at api/src/main/java/io/jsonwebtoken/lang/Assert.java:384
/**
* Assert that the provided object is an instance of the provided class.
* <pre class="code">Assert.instanceOf(Foo.class, foo);</pre>
*
* @param type the type to check against
* @param <T> the object's expected type
* @param obj the object to check
* @param message a message which will be prepended to the message produced by
* the function itself, and which may be used to provide context. It should
* normally end in a ": " or ". " so that the function generate message looks
* ok when prepended to it.
* @return the non-null object IFF it is an instance of the specified {@code type}.
* @throws IllegalArgumentException if the object is not an instance of clazz
* @see Class#isInstance
*/
public static <T> T isInstanceOf(Class<T> type, Object obj, String message) {
notNull(type, "Type to check against must not be null");
if (!type.isInstance(obj)) {
throw new IllegalArgumentException(message +
"Object of class [" + (obj != null ? obj.getClass().getName() : "null") +
"] must be an instance of " + type);
}
return type.cast(obj);
}
/**
* Asserts that the provided object is an instance of the provided class, throwing an
* {@link IllegalStateException} otherwise.
* <pre class="code">Assert.stateIsInstance(Foo.class, foo);</pre>
*
* @param type the type to check against
* @param <T> the object's expected type
* @param obj the object to check
* @param message a message which will be prepended to the message produced by
* the function itself, and which may be used to provide context. It should
* normally end in a ": " or ". " so that the function generate message looks
* ok when prepended to it.View on GitHub (pinned to fb71496164)
Solutions
- Ensure the object is an instance of the required type (implement/extend it)
- Check obj.getClass() against the expected type before the call
- Verify you are not mixing incompatible library versions (e.g. old deprecated API types)
- If using reflection/factories, cast or validate the produced instance
Example fix
// before
Object key = loadKey(); // returns Object
Jwts.builder().signWith((Key) key); // may fail isInstanceOf
// after
Key key = loadKey();
if (!(key instanceof SecretKey)) { throw new IllegalArgumentException("need SecretKey"); }
Jwts.builder().signWith((SecretKey) key); Defensive patterns
Strategy: type-guard
Validate before calling
if (obj == null || !requiredType.isInstance(obj)) {
throw new IllegalArgumentException("Expected " + requiredType.getName()
+ ", got: " + (obj == null ? "null" : obj.getClass().getName()));
} Type guard
if (!(obj instanceof SecretKey)) {
throw new IllegalArgumentException("Key must be a SecretKey");
}
SecretKey key = (SecretKey) obj; Try / catch
try {
Assert.isInstanceOf(Key.class, obj, "Invalid key: ");
} catch (IllegalArgumentException e) {
log.error("Type contract violated: {}", e.getMessage());
throw e;
} Prevention
- Program against interfaces and check instanceof before casts
- Keep library versions consistent across modules (no mixed 0.11/0.12 types)
- Validate objects returned from reflection/ServiceLoader before use
When it happens
Trigger: Passing an object of the wrong concrete type where a specific class is required, e.g. a custom Key implementation that isn't the expected interface/class, or a pluggable component (Serializer, Clock, compressor) of the wrong type handed to a builder or factory.
Common situations: Custom implementations after a library upgrade changed the expected interface; reflection-based instantiation returning a supertype; misconfigured plugins/factories returning the wrong class; mixing jjwt 0.11 and 0.12 API types on the classpath.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- ${message}${subType} is not assignable to ${superType}
- JWT Claim '<expectedClaimName>' was expected to be a Date, b
- JWK kty value must be a String. Type found: ${type}
- JWK map keys must be Strings. Encountered key '${key}' of ty
- Value must be a Map<String,?> (JSON Object). Type found: ${t
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/eed6eb69b347ef81.
Report an issue: GitHub.