apache/cassandra · error · MarshalException
Expected a map, but got a %s: %s
Error message
Expected a map, but got a %s: %s
What it means
MapType.fromJSONObject() converts a parsed JSON value into collection Terms. Because JSON objects decode to Java Maps, the value must be a Map; if it is any other type (after optionally decoding a JSON string), the library throws this MarshalException.
Source
Thrown at src/java/org/apache/cassandra/db/marshal/MapType.java:339
assert isMultiCell;
List<byte[]> bbs = new ArrayList<>();
while (cells.hasNext())
{
Cell<?> c = cells.next();
bbs.add(ByteBufferUtil.getArrayUnsafeNullable(c.path().get(0)));
bbs.add(c.valueAsArray());
}
return bbs;
}
@Override
public Term fromJSONObject(Object parsed) throws MarshalException
{
if (parsed instanceof String)
parsed = JsonUtils.decodeJson((String) parsed);
if (!(parsed instanceof Map))
throw new MarshalException(String.format(
"Expected a map, but got a %s: %s", parsed.getClass().getSimpleName(), parsed));
Map<?, ?> map = (Map<?, ?>) parsed;
List<Term> terms = new ArrayList<>(map.size() << 1);
for (Map.Entry<?, ?> entry : map.entrySet())
{
if (entry.getKey() == null)
throw new MarshalException("Invalid null key in map");
if (entry.getValue() == null)
throw new MarshalException("Invalid null value in map");
terms.add(keys.fromJSONObject(entry.getKey()));
terms.add(values.fromJSONObject(entry.getValue()));
}
return new MultiElements.DelayedValue(this, terms);
}
View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Provide a JSON object for map columns: {"1":"one"} instead of [1,2] or a scalar.
- Fix client serialization so map-typed fields emit JSON objects.
- Catch MarshalException around the JSON term conversion and validate the payload shape before submission.
Example fix
// before
INSERT INTO t (m) JSON '{"m": [1,2]}';
// after
INSERT INTO t (m) JSON '{"m": {"1":"a", "2":"b"}}'; Defensive patterns
Strategy: type-guard
Validate before calling
if (!(parsedValue instanceof Map))
throw new IllegalArgumentException("map column requires a JSON object, got: " + parsedValue); Type guard
static boolean isJsonObject(Object v) {
if (v instanceof String)
v = JsonUtils.decodeJson((String) v);
return v instanceof Map;
} Try / catch
try {
Term term = mapType.fromJSONObject(parsed);
} catch (MarshalException e) {
// reject payload; log offending value
} Prevention
- Emit JSON objects (not arrays) for map columns
- Add JSON schema validation with type: object for map fields
- Check client serializer config for map/array mapping
When it happens
Trigger: Calling fromJSONObject on MapType with a parsed Object that is not a java.util.Map — e.g. a List, Number, Boolean, or a String that fails to decode to a JSON object via JsonUtils.decodeJson.
Common situations: CQL JSON inserts where a map column is given an array or scalar instead of a JSON object; client code passing a JSON array like [1,2] to a map<int,text> column; double-encoded JSON strings.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Expected an ascii string, but got a %s: %s
- Expected a double value, but got a %s: %s
- Expected an empty string, but got: %s
- Expected a float value, but got a %s: %s
- Invalid null key in map
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/915d37f424f9d4b5.
Report an issue: GitHub.