ben-manes/caffeine · error · IllegalArgumentException
key %s invalid format; was %s, but the duration cannot be pa
Error message
key %s invalid format; was %s, but the duration cannot be parsed
What it means
When a duration option value contains 'T' (ISO-8601 marker), CaffeineSpec.parseIsoDuration delegates to Duration.parse and throws IllegalArgumentException("key %s invalid format; was %s, but the duration cannot be parsed") on DateTimeParseException. The spec string's duration must be a valid ISO-8601 duration (e.g. PT10M) or a simple form like 10m.
Source
Thrown at caffeine/src/main/java/com/github/benmanes/caffeine/cache/CaffeineSpec.java:322
static Duration parseDuration(String key, @Nullable String value) {
requireArgument((value != null) && !value.isEmpty(), "value of key %s omitted", key);
requireNonNull(value);
boolean isIsoFormat = value.contains("p") || value.contains("P");
Duration duration = isIsoFormat
? parseIsoDuration(key, value)
: parseSimpleDuration(key, value);
requireArgument(!duration.isNegative(),
"key %s invalid format; was %s, but the duration cannot be negative", key, value);
return duration;
}
/** Returns a parsed duration using the ISO-8601 format. */
static Duration parseIsoDuration(String key, String value) {
try {
return Duration.parse(value);
} catch (DateTimeParseException e) {
throw new IllegalArgumentException(String.format(US,
"key %s invalid format; was %s, but the duration cannot be parsed", key, value), e);
}
}
/** Returns a parsed duration using the simple time unit format. */
static Duration parseSimpleDuration(String key, String value) {
long duration = parseLong(key, value.substring(0, value.length() - 1));
TimeUnit unit = parseTimeUnit(key, value);
return Duration.ofNanos(unit.toNanos(duration));
}
/** Returns a parsed {@link TimeUnit} value. */
@SuppressWarnings({"ConstantValue", "StatementSwitchToExpressionSwitch"})
static TimeUnit parseTimeUnit(String key, String value) {
requireArgument((value != null) && !value.isEmpty(), "value of key %s omitted", key);
@SuppressWarnings("null")
char lastChar = Character.toLowerCase(value.charAt(value.length() - 1));
switch (lastChar) {View on GitHub (pinned to 9da6581ee3)
Solutions
- Use a complete ISO-8601 duration: expireAfterWrite=PT10M30S (the T separates date from time parts)
- Or use the simple format with a unit suffix: expireAfterWrite=10m
- When generating values programmatically, build them from Duration.toString() to guarantee validity
Example fix
# before
Caffeine.from("expireAfterWrite=P10M") // parsed as 10 months, or rejected if truncated
Caffeine.from("expireAfterWrite=PT") // IllegalArgumentException: cannot be parsed
# after
Caffeine.from("expireAfterWrite=PT10M") # 10 minutes
# or
Caffeine.from("expireAfterWrite=10m") Defensive patterns
Strategy: validation
Validate before calling
// Validate ISO durations before building the spec:
static String isoDuration(String key, Duration d) {
if (d.isNegative()) throw new ConfigException(key + " must not be negative");
return key + "=" + d; // Duration.toString() is always valid ISO-8601
}
String spec = isoDuration("expireAfterWrite", Duration.ofMinutes(10)); Try / catch
try {
return Caffeine.from(spec);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().contains("duration cannot be parsed")) {
// Fall back to builder API with a safe default
return Caffeine.newBuilder().expireAfterWrite(Duration.ofMinutes(10));
}
throw e;
} Prevention
- Remember ISO-8601 'M' after P is months, after T is minutes: PT10M = 10 minutes, P10M = 10 months
- Generate duration values from Duration.toString() rather than hand-building strings
- Negative durations are rejected separately — always supply non-negative durations
When it happens
Trigger: Caffeine.from("expireAfterWrite=PT") or "expireAfterWrite=P1D30M" (malformed ISO-8601); using ISO syntax without the T for time components, e.g. "P10M" intended as ten minutes (that is ten months in ISO); partial values like "expireAfterAccess=T30s".
Common situations: Mixing simple-format habits into ISO-8601 strings; generating spec strings from templates that drop required components; assuming 'P10M' means minutes rather than months.
Related errors
- key %s invalid format; was %s, must end with one of [dDhHmMs
- Invalid option
- key %s value was set to %s, must be an integer
- key %s value was set to %s, must be a long
- throw new ExceptionInInitializerError(e)
AI-assisted analysis of ben-manes/caffeine@9da6581ee3 (2026-08-14).
Data as JSON: /api/errors/17afa7f2ea038cf7.
Report an issue: GitHub.