{"record":{"id":"9ed68a5246e31678","repo":"jwtk/jjwt","slug":"jwk-map-keys-must-be-strings-encountered-key-k","errorCode":null,"errorMessage":"JWK map keys must be Strings. Encountered key '${key}' of type ${type}.","messagePattern":"JWK map keys must be Strings\\. Encountered key '(.+?)' of type (.+?)\\.","errorType":"validation","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/security/JwkConverter.java","lineNumber":167,"sourceCode":"        }\n        if (!(val instanceof String)) {\n            String msg = \"JWK \" + param + \" value must be a String. Type found: \" + val.getClass().getName();\n            throw new MalformedKeyException(msg);\n        }\n        String kty = (String) val;\n        if (!Strings.hasText(kty)) {\n            String msg = \"JWK \" + param + \" value cannot be empty.\";\n            throw new MalformedKeyException(msg);\n        }\n\n        DynamicJwkBuilder<?, ?> builder = this.supplier.get();\n        for (Map.Entry<?, ?> entry : map.entrySet()) {\n            Object key = entry.getKey();\n            Assert.notNull(key, \"JWK map key cannot be null.\");\n            if (!(key instanceof String)) {\n                String msg = \"JWK map keys must be Strings. Encountered key '\" + key + \"' of type \" +\n                        key.getClass().getName() + \".\";\n                throw new IllegalArgumentException(msg);\n            }\n            String skey = (String) key;\n            builder.add(skey, entry.getValue());\n        }\n        Jwk<?> jwk = builder.build();\n\n        if (desiredType.isInstance(jwk)) {\n            return desiredType.cast(jwk);\n        }\n        throw unexpectedIAE(jwk);\n    }\n}\n","sourceCodeStart":149,"sourceCodeEnd":180,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/security/JwkConverter.java#L149-L180","documentation":"JWK member names must be JSON strings. During map-to-JWK conversion, applyFrom iterates map entries and throws IllegalArgumentException (via the explicit check) if any key is not a String, and asserts no key is null.","triggerScenarios":"Passing a Map with non-String keys (e.g. Integer, enum instances) to JWK building/parsing APIs.","commonSituations":"Programmatically built maps using enum or numeric keys; converting from formats that allow non-string keys (e.g. YAML, Java Properties).","solutions":["Convert all map keys to Strings before building the JWK (e.g. enum.name(), String.valueOf(key))","Fix upstream deserialization so JSON object keys stay Strings","Use Properties.stringPropertyNames() or equivalent when copying from Properties"],"exampleFix":"// before\nMap<Object,Object> m = props; // contains Integer keys\nbuilder.build(m);\n// after\nMap<String,Object> m = props.entrySet().stream()\n    .collect(Collectors.toMap(e -> String.valueOf(e.getKey()), Map.Entry::getValue));\nbuilder.build(m);","handlingStrategy":"type-guard","validationCode":"for (Object k : jwkMap.keySet()) { if (!(k instanceof String)) throw new IllegalArgumentException(\"All JWK keys must be Strings\"); }","typeGuard":"boolean allStringKeys(Map<?,?> m) { return m != null && m.keySet().stream().allMatch(k -> k instanceof String); }","tryCatchPattern":"try { jwk = converter.applyFrom(map); } catch (IllegalArgumentException e) { log.error(\"Bad JWK map keys: {}\", e.getMessage()); }","preventionTips":["Always build JWK maps as Map<String,Object>","Convert Properties/YAML keys with String.valueOf before use"],"tags":["jwt","jwk","type-mismatch","map-keys"],"backgroundTag":"type-mismatch","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}