apache/cassandra · error · MarshalException

Expected a list representation of a tuple, but got a

Error message

Expected a list representation of a tuple, but got a %s: %s

What it means

TupleType.fromJSONObject converts a parsed JSON value into a tuple Term. The JSON must be a list whose elements map to the tuple's fields. If the parsed object is not a List (e.g. a string, map, or number), this MarshalException is thrown with the value's Java class name and contents.

Solutions

  1. Send the tuple as a JSON array: [elem1, elem2, ...]
  2. Fix double-encoding by passing the parsed JSON structure, not a JSON string containing JSON
  3. Check the client serializer's mapping for tuple columns
  4. Validate the payload shape before INSERT JSON

Example fix

// before
{"t": {"0": 1, "1": 2}}
// after
{"t": [1, 2]}
Defensive patterns

Strategy: type-guard

Validate before calling

Object parsed = JsonUtils.decodeJson(json);
if (!(parsed instanceof List)) throw new IllegalArgumentException("tuple JSON must be an array");

Type guard

boolean isTupleJson(Object parsed) { return parsed instanceof List; }

Try / catch

try {
    Term t = tupleType.fromJSONObject(parsed);
} catch (MarshalException e) {
    throw new IllegalArgumentException("tuple JSON shape invalid: " + e.getMessage());
}

Prevention

When it happens

Trigger: Inserting JSON where the tuple column is given an object/map instead of an array (e.g. {"t": {"a":1}} instead of {"t": [1,2]}); passing a JSON-encoded string that decodes to a non-list to fromJSONObject.

Common situations: Application JSON serializers emitting maps for tuples; double-encoded JSON strings (a string containing JSON) where decodeJson produces a scalar; cqlsh INSERT JSON with a malformed tuple field.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/0eb030cff7076be8. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/db/marshal/TupleType.java:495

            else
            {
                AbstractType<?> type = type(i);
                fieldString = ESCAPED_COLON_PAT.matcher(fieldString).replaceAll(COLON);
                fieldString = ESCAPED_AT_PAT.matcher(fieldString).replaceAll(AT);
                fields.add(type.fromString(fieldString));
            }
        }
        return pack(fields);
    }

    @Override
    public Term fromJSONObject(Object parsed) throws MarshalException
    {
        if (parsed instanceof String)
            parsed = JsonUtils.decodeJson((String) parsed);

        if (!(parsed instanceof List))
            throw new MarshalException(String.format(
                    "Expected a list representation of a tuple, but got a %s: %s", parsed.getClass().getSimpleName(), parsed));

        List<?> list = (List<?>) parsed;

        if (list.size() > types.size())
            throw new MarshalException(String.format("Tuple contains extra items (expected %s): %s", types.size(), parsed));
        else if (types.size() > list.size())
            throw new MarshalException(String.format("Tuple is missing items (expected %s): %s", types.size(), parsed));

        List<Term> terms = new ArrayList<>(list.size());
        Iterator<AbstractType<?>> typeIterator = types.iterator();
        for (Object element : list)
        {
            if (element == null)
            {
                typeIterator.next();
                terms.add(Constants.NULL_VALUE);
            }

View on GitHub (pinned to 88fd0f6a0e)