jwtk/jjwt · error · IllegalArgumentException

Unsupported value type. Expected: ${type.getName()}, found:

Error message

Unsupported value type. Expected: ${type.getName()}, found: ${clazz.getName()}

What it means

RequiredTypeConverter.applyFrom checks that a claim value's runtime class is assignable to the configured target type before calling type.cast(o). If not, it throws this IllegalArgumentException naming the expected and actual class names. Null values pass through and return null.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/lang/RequiredTypeConverter.java:44

    public RequiredTypeConverter(Class<T> type) {
        this.type = Assert.notNull(type, "type argument cannot be null.");
    }

    @Override
    public Object applyTo(T t) {
        return t;
    }

    @Override
    public T applyFrom(Object o) {
        if (o == null) {
            return null;
        }
        Class<?> clazz = o.getClass();
        if (!type.isAssignableFrom(clazz)) {
            String msg = "Unsupported value type. Expected: " + type.getName() + ", found: " + clazz.getName();
            throw new IllegalArgumentException(msg);
        }
        return type.cast(o);
    }
}

View on GitHub (pinned to fb71496164)

Solutions

  1. Convert the value to the expected type before setting it (e.g. new Date(...) instead of an ISO string).
  2. Check the class with type.isInstance(value) before assignment to fail fast.
  3. Fix the source map/serialization so types survive round-trips correctly.

Example fix

// before
jwtBuilder.claim("iat", "2026-09-08T12:00:00Z"); // String, expected Date
// after
jwtBuilder.claim("iat", new Date());
Defensive patterns

Strategy: type-guard

Validate before calling

void checkClaimType(Map<String,Object> claims, Class<?> type) {
    for (Map.Entry<String,Object> e : claims.entrySet()) {
        if (e.getValue() != null && !type.isInstance(e.getValue())
                && !type.isAssignableFrom(e.getValue().getClass())) {
            throw new IllegalArgumentException("Claim '" + e.getKey() + "' expected " + type.getName());
        }
    }
}

Type guard

<T> boolean isOfType(Object o, Class<T> type) {
    return o == null || type.isInstance(o);
}

Try / catch

try {
    converter.applyFrom(value);
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Unsupported value type.")) {
        // parse the expected/found class names from the message to fix the value
    }
    throw e;
}

Prevention

When it happens

Trigger: Setting a claim value whose Java type does not match the converter's expected type, e.g. putting a String into a claim that must be a Date, or an Integer where a List is required.

Common situations: Copying claims from external JSON maps with loose typing; generic Map<String,Object> building where the wrong value slipped in; serialization round-trips that changed types (e.g. Date became String).

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/8532e2bae9212339. Report an issue: GitHub.