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

  1. Send the duration as a string using Cassandra duration syntax, e.g. "12h30m" or "P1Y2M3DT4H5M6S"
  2. Convert numeric durations to a duration string (e.g. 3 -> "3mo" only if that matches intended unit) before inserting
  3. 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

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


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)