jwtk/jjwt · error · IllegalArgumentException

Values must be either String or ${type.getName()} instances.

Error message

Values must be either String or ${type.getName()} instances. Value type found: ${value.getClass().getName()}.

What it means

EncodedObjectConverter.applyFrom converts a raw input value into the target encoded object type (e.g. TextCodec-decoded byte arrays). It accepts only the target type itself or a CharSequence (interpreted as its encoded String form); any other type throws IllegalArgumentException stating the accepted value types and the offending runtime type.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/lang/EncodedObjectConverter.java:46

    }

    @Override
    public Object applyTo(T t) {
        Assert.notNull(t, "Value argument cannot be null.");
        return converter.applyTo(t);
    }

    @Override
    public T applyFrom(Object value) {
        Assert.notNull(value, "Value argument cannot be null.");
        if (type.isInstance(value)) {
            return type.cast(value);
        } else if (value instanceof CharSequence) {
            return converter.applyFrom((CharSequence) value);
        } else {
            String msg = "Values must be either String or " + type.getName() +
                    " instances. Value type found: " + value.getClass().getName() + ".";
            throw new IllegalArgumentException(msg);
        }
    }
}

View on GitHub (pinned to fb71496164)

Solutions

  1. Convert the value to String (or the exact target type) before passing: String.valueOf(v) or Base64 encoder.
  2. Ensure byte[] values are passed as byte[], and textual encodings as String - don't pass wrapper/container objects.
  3. Normalize JSON-parsed values: coerce Numbers/containers to the expected textual form.

Example fix

// before
byte[] key = converter.applyFrom(secretMap.get("k")); // Integer
// after
Object v = secretMap.get("k");
byte[] key = converter.applyFrom(v instanceof byte[] ? v : String.valueOf(v));
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(value instanceof CharSequence) && !(value instanceof byte[])) {
    value = String.valueOf(value);
}

Type guard

static boolean isEncodable(Object v) {
    return v instanceof CharSequence || v instanceof byte[];
}

Try / catch

try {
    T obj = converter.applyFrom(value);
} catch (IllegalArgumentException e) {
    // convert value to String/target type and retry
}

Prevention

When it happens

Trigger: Passing a byte[]-incompatible object (Integer, Map, JSONObject, null-wrapped boxed types) where a String or the target encoded object is expected, e.g. setting a key/secret/IV claim with a non-String, non-byte-array value.

Common situations: Reading claim values from a JSON library that yields JSONArray/JSONObject or Numbers instead of Strings; passing Base64-decoded byte[] where a Base64 String is expected (or vice versa); wrong claim type after a schema change.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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