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

  1. Log/print the cause message to see the underlying parse problem and fix the JSON source.
  2. Verify the JWKS endpoint returns application/json with a top-level object containing a "keys" array.
  3. Re-fetch the document; check for proxies/CDN error pages replacing the JSON.
  4. 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

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.

Related errors


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