jwtk/jjwt · error · IllegalStateException

Unable to read field

Error message

Unable to read field ${instanceClassName}#${fieldName}: ${causeMessage}

What it means

IllegalStateException thrown by io.jsonwebtoken.lang.Classes.getFieldValue when reflectively reading a declared field fails — field not found, setAccessible rejected, wrong fieldType cast, or instance/class mismatch. The message embeds the underlying cause message.

Solutions

  1. Verify the field name and type against the exact jar version on the classpath
  2. Use the library's public API instead of reading internal fields
  3. For JDK 9+, add --add-opens / module opens if access is intentional and unavoidable
  4. Match fieldType to the field's declared type to avoid the cast failure

Example fix

// before
String alg = Classes.getFieldValue(header, "algx", String.class); // wrong field name
// after
String alg = Classes.getFieldValue(header, "alg", String.class);
Defensive patterns

Strategy: try-catch

Validate before calling

try {
    java.lang.reflect.Field f = instance.getClass().getDeclaredField(fieldName);
    if (!fieldType.isAssignableFrom(f.getType())) {
        throw new IllegalArgumentException("Field " + fieldName + " is not " + fieldType);
    }
} catch (NoSuchFieldException e) {
    throw new IllegalArgumentException("No field " + fieldName + " on " + instance.getClass());
}

Try / catch

try {
    return Classes.getFieldValue(instance, fieldName, fieldType);
} catch (IllegalStateException e) {
    LOG.warn("Reflective field read failed for {}.#{}, cause: {}", instance.getClass(), fieldName, e.getCause());
    return defaultValue;
}

Prevention

When it happens

Trigger: getFieldValue(instance, fieldName, fieldType) where fieldName does not exist on instance's class, a SecurityManager/module system blocks setAccessible, or field.get returns an object not castable to fieldType.

Common situations: Poking at library internals whose field names changed between jjwt versions; JDK 9+ strong encapsulation denying access to private fields of non-exported packages; wrong expected type parameter causing ClassCastException.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at api/src/main/java/io/jsonwebtoken/lang/Classes.java:352

     * Returns the {@code instance}'s named (declared) field value.
     *
     * @param instance  the instance with the internal field
     * @param fieldName the name of the field to inspect
     * @param fieldType the type of field to inspect
     * @param <T>       field instance value type
     * @return the field value
     */
    public static <T> T getFieldValue(Object instance, String fieldName, Class<T> fieldType) {
        if (instance == null) return null;
        try {
            Field field = instance.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            Object o = field.get(instance);
            return fieldType.cast(o);
        } catch (Throwable t) {
            String msg = "Unable to read field " + instance.getClass().getName() +
                    "#" + fieldName + ": " + t.getMessage();
            throw new IllegalStateException(msg, t);
        }
    }

    /**
     * @since 1.0
     */
    private interface ClassLoaderAccessor {
        Class<?> loadClass(String fqcn);

        URL getResource(String name);

        InputStream getResourceStream(String name);
    }

    /**
     * @since 1.0
     */
    private static abstract class ExceptionIgnoringAccessor implements ClassLoaderAccessor {

View on GitHub (pinned to fb71496164)