apache/pulsar · error · IllegalArgumentException
Invalid time unit '<lastChar>'
Error message
Invalid time unit '<lastChar>'
What it means
RelativeTimeUtil.parseRelativeTimeInSeconds parses strings like '60s', '5m', '2h', '7d', '2w', '1y' into seconds. The last character is taken as the time unit; if it is alphabetic but not one of s/m/h/d/w/y (case-insensitive), the parser throws this IllegalArgumentException. Note that months are intentionally unsupported, so 'M' and other letters like 'x' or 'z' are rejected.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/RelativeTimeUtil.java:65
long duration = Long.parseLong(relativeTime.substring(0, lastIndex));
switch (timeUnit) {
case 's':
return duration;
case 'm':
return TimeUnit.MINUTES.toSeconds(duration);
case 'h':
return TimeUnit.HOURS.toSeconds(duration);
case 'd':
return TimeUnit.DAYS.toSeconds(duration);
case 'w':
return 7 * TimeUnit.DAYS.toSeconds(duration);
// No unit for months
case 'y':
return 365 * TimeUnit.DAYS.toSeconds(duration);
default:
throw new IllegalArgumentException("Invalid time unit '" + lastChar + "'");
}
}
/**
* Convert nanoseconds to seconds and keep three decimal places.
* @param ns
* @return seconds
*/
public static double nsToSeconds(long ns) {
double seconds = (double) ns / 1_000_000_000;
BigDecimal bd = new BigDecimal(seconds);
return bd.setScale(3, RoundingMode.HALF_UP).doubleValue();
}
}
View on GitHub (pinned to 820761864e)
Solutions
- Fix the input string to use only supported units: s, m, h, d, w, or y (e.g. '30m' instead of '30M').
- Express months as days or weeks (e.g. '30d') since months are not a supported unit.
- Strip surrounding whitespace/typos so the string ends with a valid single-letter unit.
- Validate the unit character before calling the parser in user-facing code.
Example fix
// before
long seconds = RelativeTimeUtil.parseRelativeTimeInSeconds("30M");
// after
long seconds = RelativeTimeUtil.parseRelativeTimeInSeconds("30d"); Defensive patterns
Strategy: validation
Validate before calling
private static final java.util.Set<Character> VALID_UNITS = java.util.Set.of('s','m','h','d','w','y');
static long safeParseRelativeTime(String input) {
String trimmed = input.trim();
if (trimmed.isEmpty()) throw new IllegalArgumentException("expiry time cannot be empty");
char last = Character.toLowerCase(trimmed.charAt(trimmed.length() - 1));
if (Character.isAlphabetic(last) && !VALID_UNITS.contains(last)) {
throw new IllegalArgumentException("Invalid time unit '" + last + "'; use s, m, h, d, w, or y");
}
return RelativeTimeUtil.parseRelativeTimeInSeconds(trimmed);
} Type guard
static boolean isValidRelativeTimeString(String s) {
if (s == null || s.isEmpty()) return false;
char last = Character.toLowerCase(s.charAt(s.length() - 1));
if (!Character.isAlphabetic(last)) return true; // no unit -> seconds
return "smdwy".indexOf(last) >= 0;
} Try / catch
try {
long seconds = RelativeTimeUtil.parseRelativeTimeInSeconds(userInput);
} catch (IllegalArgumentException e) {
LOG.error("Invalid relative time '{}' (units: s, m, h, d, w, y)", userInput, e);
throw new ConfigurationException("Invalid time value: " + userInput, e);
} Prevention
- Only use supported unit suffixes s, m, h, d, w, y in configs and user input
- Remember months are not supported — express months as days (e.g. '30d')
- Trim and normalize user-provided time strings before parsing
- Validate the trailing unit character in config-loading code before calling the parser
When it happens
Trigger: Calling parseRelativeTimeInSeconds with a string ending in a letter other than s, m, h, d, w, or y (e.g. '30M' for minutes uppercase-collision concerns or months, '1mo', '10x', '5min'). Any user/config supplied relative time value (e.g. TTL, retention, expiry settings) with an unrecognized unit suffix.
Common situations: Users write '30M' or '1mo' expecting months or minutes; config files carry units like 'ms', 'min', or 'sec' carried over from other tools; typo in unit suffix ('2hh'); locale or copy-paste issues introduce odd trailing characters.
Related errors
- Invalid auto split/merge configuration: ${message}
- At least one of maxNumMessages, maxNumBytes, timeout must be
- Broker doesn't allow forced deletion of namespaces
- Local cluster is not part of replicate cluster list
- ResourceGroupCreate: Invalid null ResourceGroup config
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/7b5b6c64a1be205a.
Report an issue: GitHub.