apache/cassandra · error · MarshalException
Expected a string representation of a duration, but got a
Error message
Expected a string representation of a duration, but got a %s: %s
What it means
DurationType.fromJSONObject() requires the parsed JSON value to be a String, because durations are canonically written as strings like '12h30m' or 'P1Y2M'. If the JSON value is not a String (number, boolean, object, null), ClassCastException is caught and a MarshalException is thrown stating what type was actually received. Durations intentionally do not accept raw numeric JSON values.
Solutions
- Send the duration as a string using Cassandra duration syntax, e.g. "12h30m" or "P1Y2M3DT4H5M6S"
- Convert numeric durations to a duration string (e.g. 3 -> "3mo" only if that matches intended unit) before inserting
- Fix client serialization so java.time.Duration / custom duration types emit Cassandra-compatible strings
Example fix
// before
{"ttl_duration": 3600}
// after
{"ttl_duration": "1h"} Defensive patterns
Strategy: type-guard
Validate before calling
if (!(value instanceof String)) throw new IllegalArgumentException("Duration columns require a string like '12h30m'"); Type guard
boolean isDurationString(Object v) { return v instanceof String && ((String) v).matches("(\\d+(mo|d|h|m|s|ms|us|ns|y))+"); } Try / catch
try { term = DurationType.instance.fromJSONObject(parsed); } catch (MarshalException e) { log.error("Duration must be a string: {}", parsed); } Prevention
- Serialize java.time.Duration to Cassandra duration strings, never epoch numbers
- Document duration column format for client teams
- Add payload validation before INSERT JSON
When it happens
Trigger: INSERT JSON / fromJSONObject with a duration column given as a number (e.g. {"dur": 3}) or an object, rather than a duration string like "3h".
Common situations: Clients encode durations as seconds/milliseconds numbers; ORMs serialize Duration objects to numeric epoch values instead of ISO-8601-like duration strings; schema migration from a bigint column to duration keeps old numeric payloads.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Error decoding JSON:
- Expected a boolean value, but got a
- Expected a byte value, but got a
- Expected a double value, but got a
- Expected a float value, but got a
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/e2f5b18451820e97.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/db/marshal/DurationType.java:72
return decompose(Duration.from(source));
}
@Override
public boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
{
return this == otherType;
}
public Term fromJSONObject(Object parsed) throws MarshalException
{
try
{
return new Constants.Value(fromString((String) parsed));
}
catch (ClassCastException exc)
{
throw new MarshalException(String.format("Expected a string representation of a duration, but got a %s: %s",
parsed.getClass().getSimpleName(), parsed));
}
}
@Override
public TypeSerializer<Duration> getSerializer()
{
return DurationSerializer.instance;
}
@Override
public ArgumentDeserializer getArgumentDeserializer()
{
return ARGUMENT_DESERIALIZER;
}
@Override
public CQL3Type asCQL3Type()View on GitHub (pinned to 88fd0f6a0e)