jwtk/jjwt · error · MalformedKeySetException
Malformed JWK Set JSON: ${t.getMessage()}
Error message
Malformed JWK Set JSON: ${t.getMessage()} What it means
JwkSetDeserializer.malformed wraps any Throwable raised while deserializing JWK Set JSON into a MalformedKeySetException with the message "Malformed JWK Set JSON: <cause>". It signals the input JSON could not be parsed or did not satisfy JWK Set requirements.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/JwkSetDeserializer.java:31
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jsonwebtoken.impl.security;
import io.jsonwebtoken.impl.io.JsonObjectDeserializer;
import io.jsonwebtoken.io.Deserializer;
import io.jsonwebtoken.security.MalformedKeySetException;
public class JwkSetDeserializer extends JsonObjectDeserializer {
public JwkSetDeserializer(Deserializer<?> deserializer) {
super(deserializer, "JWK Set");
}
@Override
protected RuntimeException malformed(Throwable t) {
String msg = "Malformed JWK Set JSON: " + t.getMessage();
throw new MalformedKeySetException(msg, t);
}
}
View on GitHub (pinned to fb71496164)
Solutions
- Log/print the cause message to see the underlying parse problem and fix the JSON source.
- Verify the JWKS endpoint returns application/json with a top-level object containing a "keys" array.
- Re-fetch the document; check for proxies/CDN error pages replacing the JSON.
- Validate the JSON with a linter or json parser before feeding it to the deserializer.
Example fix
// before
String body = new String(response.getBytes()); // may be HTML error page
JwkSet set = deserialize(body);
// after
if (!body.trim().startsWith("{")) {
throw new IllegalStateException("JWKS endpoint returned non-JSON: " + body.substring(0, Math.min(100, body.length())));
}
JwkSet set = deserialize(body); Defensive patterns
Strategy: try-catch
Validate before calling
boolean isJsonObject(String s) {
try { new JSONTokener(s).nextValue(); return s.trim().startsWith("{"); }
catch (JSONException e) { return false; }
} Try / catch
try {
jwkSet = deserializer.deserialize(json);
} catch (MalformedKeySetException e) {
logger.error("JWKS document invalid: {}", e.getMessage());
// re-fetch from issuer or fail closed
} Prevention
- Check HTTP content-type is application/json before parsing JWKS responses.
- Detect HTML error pages (status != 200 or body not starting with '{') before deserializing.
- Cache the last-known-good JWKS as a fallback.
When it happens
Trigger: Calling the deserializer with JSON that is not a valid JWK Set: syntactically invalid JSON, JSON that is not an object, a missing "keys" array, or entries that fail validation during deserialization.
Common situations: JWKS endpoint returning an HTML error page instead of JSON; truncated response body; wrong URL configured for the issuer's JWKS; serving a single JWK object instead of a Set.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Unable to deserialize: ${t.getMessage()}
- Deserialized data resulted in a null value; cannot create Ma
- Deserialized data is not a JSON Object; cannot create Map<St
- Malformed or excessively complex ${name} JSON. If experience
- Malformed ${name} JSON: ${t.getMessage()}
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/8c0148f3c9bcd07d.
Report an issue: GitHub.