jwtk/jjwt · error · java.lang.IllegalStateException
Both 'zip()' and 'compressionCodecResolver' cannot be…
Error message
Both 'zip()' and 'compressionCodecResolver' cannot be configured. Choose either.
What it means
JwtParser.build() forbids configuring both the zip(...) algorithm set and a custom compressionCodecResolver, since they are two competing ways to decide how compressed JWT payloads are decompressed. The builder throws IllegalStateException to resolve the ambiguity up front rather than during parsing.
Solutions
- Remove compressionCodecResolver(...) and keep zip(...) for standard algorithm selection
- Remove zip(...) and keep compressionCodecResolver(...) for fully custom resolution
- Audit the builder construction path so only one compression configuration mechanism is used
Example fix
// before
JwtParser parser = Jwts.parser()
.zip(Jwts.ZIP.DEF) // plus leftover:
.compressionCodecResolver(resolver)
.build();
// after
JwtParser parser = Jwts.parser()
.zip(Jwts.ZIP.DEF)
.build(); Defensive patterns
Strategy: validation
Validate before calling
if (codecResolver != null && zipAlgs != null) {
throw new IllegalArgumentException("Use either zip() or compressionCodecResolver, not both");
} Try / catch
try {
JwtParser p = builder.build();
} catch (IllegalStateException e) {
log.error("Compression config conflict: {}", e.getMessage());
} Prevention
- Use zip() for standard algorithms and only drop to a custom resolver when truly needed
- Strip old resolver configuration when adopting the zip() API
- Add a parser-builder unit test asserting build() succeeds
When it happens
Trigger: Calling JwtParserBuilder.zip(algorithms) and compressionCodecResolver(resolver) on the same builder, then build().
Common situations: Adding a custom codec resolver for a non-standard compression algorithm while a zip(...) whitelist from earlier code remains; wrapping legacy builder code where the newer zip() API was layered over an old resolver.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- Both 'keyLocator' and a 'verifyWith' key cannot be…
- 'unsecuredDecompression' is only relevant if 'unsecured' is…
- Unsupported algorithm... is disabled (no algorithms have…
- 'b64' Unencoded payload option has been specified, but…
- Both a 'signingKeyResolver and a 'verifyWith' key cannot be…
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/db8f49655c338b6f.
Report an issue: GitHub.
Appendix: source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParserBuilder.java:403
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);
}
if (!unsecured && unsecuredDecompression) {
String msg = "'unsecuredDecompression' is only relevant if 'unsecured' is also " +
"configured. Please read the JavaDoc of both features before enabling either " +
"due to their security implications.";
throw new IllegalStateException(msg);
}
if (this.compressionCodecResolver != null && !Jwts.ZIP.get().equals(this.zipAlgs)) {
String msg = "Both 'zip()' and 'compressionCodecResolver' " +
"cannot be configured. Choose either.";
throw new IllegalStateException(msg);
}
// Invariants. If these are ever violated, it's an error in this class implementation:
Assert.stateNotNull(keyLocator, "Key locator should never be null.");
final DefaultClaims expClaims = (DefaultClaims) this.expectedClaims.build();
return new DefaultJwtParser(
provider,
signingKeyResolver,
unsecured,
unsecuredDecompression,
keyLocator,
clock,
critical,
allowedClockSkewMillis,
expClaims,
decoder,View on GitHub (pinned to fb71496164)