apache/iceberg · error · IllegalArgumentException
Cannot parse to a duration string value: %s: %s
Error message
Cannot parse to a duration string value: %s: %s
What it means
JsonUtil.getDurationStringOrNull(property, node) verifies that the given JSON field is a string parseable by java.time.Duration.parse. If the value is present but not a valid ISO-8601 duration, it throws IllegalArgumentException naming the property and offending value.
Source
Thrown at core/src/main/java/org/apache/iceberg/util/JsonUtil.java:201
return null;
}
JsonNode pNode = node.get(property);
if (pNode != null && pNode.isNull()) {
return null;
}
return getString(property, node);
}
public static String getDurationStringOrNull(String property, JsonNode node) {
String value = getStringOrNull(property, node);
if (value == null) {
return null;
}
try {
java.time.Duration.parse(value);
} catch (RuntimeException e) {
throw new IllegalArgumentException(
String.format(
"Cannot parse to a duration string value: %s: %s", property, node.get(property)),
e);
}
return value;
}
public static ByteBuffer getByteBufferOrNull(String property, JsonNode node) {
if (!node.has(property) || node.get(property).isNull()) {
return null;
}
JsonNode pNode = node.get(property);
Preconditions.checkArgument(
pNode.isTextual(), "Cannot parse byte buffer from non-text value: %s: %s", property, pNode);
return ByteBuffer.wrap(
BaseEncoding.base16().decode(pNode.textValue().toUpperCase(Locale.ROOT)));View on GitHub (pinned to 86d9c8fc54)
Solutions
- Change the value to a valid ISO-8601 duration, e.g. 'PT10M' for 10 minutes or 'PT1H30S'
- Use java.time.Duration.toString() or Duration.of(...).toString() when generating config JSON
- Validate the string with Duration.parse() before writing it into the config
Example fix
// before
{ "history.expire.max-snapshot-age": "10 minutes" }
// after
{ "history.expire.max-snapshot-age": "PT10M" } Defensive patterns
Strategy: validation
Validate before calling
String v = jsonNode.get("history.expire.max-snapshot-age").asText();
java.time.Duration.parse(v); // throws DateTimeParseException if invalid Type guard
boolean isIsoDuration(String s) { try { java.time.Duration.parse(s); return true; } catch (Exception e) { return false; } } Try / catch
try { Duration d = JsonUtil.getDurationStringOrNull(prop, node) ...; } catch (IllegalArgumentException e) { /* fix config value to ISO-8601 */ } Prevention
- Always write durations as ISO-8601 strings (PT10M, PT1H)
- Use Duration.toString() when serializing to JSON
- Add schema/config validation on ingestion
When it happens
Trigger: Passing a config field like 'history.expire.max-snapshot-age-ms'-style durations as '5 minutes' or '5' instead of the ISO-8601 form 'PT5M' in JSON table metadata or catalog config.
Common situations: Hand-edited JSON config files using human-readable duration strings; tooling that writes durations without the required PT prefix; timezone/locale-specific formatting leaking into config.
Understand the failure class
Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.
Related errors
- Invalid field ID for content stats: %s
- Invalid partition data for content file: expected array or o
- Invalid file content value: '%s'
- Unknown task type:
- Cannot parse default as a %s value: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/ea8d9a4183bc64ac.
Report an issue: GitHub.