jwtk/jjwt · error · IllegalStateException
Both a 'signingKeyResolver and a 'verifyWith' key cannot be…
Error message
Both a 'signingKeyResolver and a 'verifyWith' key cannot be configured. Choose either, or prefer `keyLocator` when possible.
What it means
Thrown as IllegalStateException from DefaultJwtParserBuilder.build() when both a SigningKeyResolver and an explicit verifyWith key have been configured. These two key sources are mutually exclusive for JWS verification — the builder cannot decide which to use — so building the parser fails fast.
Solutions
- Remove the setSigningKeyResolver(...) call if all tokens are verified with one static key.
- Remove verifyWith(...) if the resolver is needed to select keys per-token (e.g. per-kid lookup).
- Prefer keyLocator (per the message) for dynamic key selection; ensure resolver/verifyWith are unset when using it.
- Guard shared configuration code so exactly one of {keyLocator, signingKeyResolver, signatureVerificationKey} is set — assert before build().
Example fix
// before
Jwts.parser()
.setSigningKeyResolver(resolver)
.verifyWith(publicKey) // conflicts
.build();
// after
Jwts.parser().verifyWith(publicKey).build();
// or for per-token key choice:
Jwts.parser().keyLocator(locate -> byKid(locate.getHeader().get("kid", String.class))).build(); Defensive patterns
Strategy: validation
Validate before calling
// before build(): ensure exactly one JWS key source is configured
int sources = (resolver != null ? 1 : 0) + (verifyKey != null ? 1 : 0) + (keyLocator != null ? 1 : 0);
if (sources > 1) throw new IllegalStateException("Configure only one of signingKeyResolver/verifyWith/keyLocator"); Try / catch
try {
JwtParser parser = Jwts.parser().verifyWith(key).build();
} catch (IllegalStateException e) {
// conflicting key configuration; strip resolver or verifyWith
} Prevention
- Configure exactly one JWS key source per parser: keyLocator, signingKeyResolver, OR verifyWith
- When migrating from signingKeyResolver to verifyWith, delete the old call completely
- Centralize parser construction in one factory method to avoid accumulating settings
- Prefer keyLocator for dynamic (per-kid) key selection in new code
When it happens
Trigger: parserBuilder().setSigningKeyResolver(resolver).verifyWith(key)...build(); typically after adding verifyWith to existing resolver-based code, or when shared builder-configuration code sets both.
Common situations: Gradual migration from the deprecated signingKeyResolver API to verifyWith leaving both set; framework/interceptor code that configures a resolver conditionally while other code sets a static key; copy-pasted parser configuration accumulating settings.
Related errors
- 'b64' Unencoded payload option has been specified, but…
- Both 'content' and 'claims' cannot be specified. Choose…
- Both 'keyLocator' and a 'verifyWith' key cannot be…
- Both 'signWith' and 'encryptWith' cannot be specified…
- Both 'zip()' and 'compressionCodecResolver' cannot be…
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/b1260071417845de.
Report an issue: GitHub.
Appendix: source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java:374
@SuppressWarnings("deprecation")
@Override
public JwtParserBuilder setCompressionCodecResolver(CompressionCodecResolver resolver) {
this.compressionCodecResolver = Assert.notNull(resolver, "CompressionCodecResolver cannot be null.");
return this;
}
@Override
public JwtParser build() {
if (this.deserializer == null) {
//noinspection unchecked
json(Services.get(Deserializer.class));
}
if (this.signingKeyResolver != null && this.signatureVerificationKey != null) {
String msg = "Both a 'signingKeyResolver and a 'verifyWith' key cannot be configured. " +
"Choose either, or prefer `keyLocator` when possible.";
throw new IllegalStateException(msg);
}
if (this.keyLocator != null) {
if (this.signatureVerificationKey != null) {
String msg = "Both 'keyLocator' and a 'verifyWith' key cannot be configured. " +
"Prefer 'keyLocator' if possible.";
throw new IllegalStateException(msg);
}
if (this.decryptionKey != null) {
String msg = "Both 'keyLocator' and a 'decryptWith' key cannot be configured. " +
"Prefer 'keyLocator' if possible.";
throw new IllegalStateException(msg);
}
}
Locator<? extends Key> keyLocator = this.keyLocator; // user configured default, don't overwrite to ensure further build() calls work as expected
if (keyLocator == null) {
keyLocator = new ConstantKeyLocator(this.signatureVerificationKey, this.decryptionKey);
}View on GitHub (pinned to fb71496164)