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

  1. Ensure the object is an instance of the required type (implement/extend it)
  2. Check obj.getClass() against the expected type before the call
  3. Verify you are not mixing incompatible library versions (e.g. old deprecated API types)
  4. 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

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


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/eed6eb69b347ef81. Report an issue: GitHub.