apache/cassandra · error · MarshalException
The data cannot be deserialized as a list
Error message
The data cannot be deserialized as a list
What it means
ListSerializer.deserialize() reads a signed 32-bit element count from the head of the buffer; a negative count cannot represent a valid list, so this MarshalException is thrown. A negative count almost always indicates corrupted or mis-framed bytes (e.g. wrong offset, wrong endianness, or deserializing a non-list blob as a list).
Source
Thrown at src/java/org/apache/cassandra/serializers/ListSerializer.java:103
if (!accessor.isEmptyFromOffset(input, offset))
throw new MarshalException("Unexpected extraneous bytes after list value");
}
catch (BufferUnderflowException | IndexOutOfBoundsException e)
{
throw new MarshalException("Not enough bytes to read a list");
}
}
@Override
public <V> List<T> deserialize(V input, ValueAccessor<V> accessor)
{
try
{
int n = readCollectionSize(input, accessor);
int offset = sizeOfCollectionSize();
if (n < 0)
throw new MarshalException("The data cannot be deserialized as a list");
// If the received bytes are not corresponding to a list, n might be a huge number.
// In such a case we do not want to initialize the list with that size as it can result
// in an OOM (see CASSANDRA-12618). On the other hand we do not want to have to resize the list
// if we can avoid it, so we put a reasonable limit on the initialCapacity.
List<T> l = new ArrayList<>(Math.min(n, 256));
for (int i = 0; i < n; i++)
{
// CASSANDRA-6839: "We can have nulls in lists that are used for IN values"
// CASSANDRA-8613 checks IN clauses and throws an exception if null is in the list.
// Leaving for this as-is for now in case there is some unknown use
// for it, but should likely be changed to readNonNull. Validate has been
// changed to throw on null elements as otherwise it would NPE, and it's unclear
// if callers could handle null elements.
V databb = readValue(input, accessor, offset);
offset += sizeOfValue(databb, accessor);
if (databb != null)
{View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Confirm the column/type is actually list (not map/set/frozen variant) and deserialize with the matching serializer.
- Dump the first bytes (toHex) and verify the count header; fix writer endianness/count encoding if wrong.
- Re-serialize the data from the source of truth; corrupted at-rest data needs a rewrite (repair/scrub or re-ETL).
- Guard callers by validating with ListSerializer.validate() before deserialize to get an earlier, clearer failure.
Example fix
// before List<Integer> l = ListSerializer.instance.deserialize(mysteryBlob, ByteBufferUtil.NONE); // after ListSerializer.instance.validate(mysteryBlob, ByteBufferUtil.NONE); // throws descriptive MarshalException first List<Integer> l = ListSerializer.instance.deserialize(mysteryBlob, ByteBufferUtil.NONE);
Defensive patterns
Strategy: try-catch
Validate before calling
int count = blob.getInt(blob.position()); if (count < 0) throw new MarshalException("negative list count: " + count); Type guard
boolean isPlausibleListBlob(java.nio.ByteBuffer b) { return b != null && b.remaining() >= 4 && b.getInt(b.position()) >= 0; } Try / catch
try { return listSerializer.deserialize(blob, accessor); } catch (org.apache.cassandra.exceptions.MarshalException e) { log.error("cannot deserialize list: {}", e.getMessage()); return Collections.emptyList(); } Prevention
- Verify the target type is actually a list before using ListSerializer
- Check endianness/count encoding on the writer side
- Call validate() before deserialize in ingestion paths
When it happens
Trigger: Calling ListSerializer.deserialize(input, accessor) where the first 4 bytes, interpreted as an int, are negative (high bit set) — e.g. deserializing a random blob, a map/set, or bytes with wrong endianness as a list.
Common situations: Casting a map or set blob to a list type; byte-order mismatch between writer and reader; reading stale SSTable data after a serialization format change; application bugs writing a raw int (e.g. -1 sentinel) where a list count belongs.
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
- null is not supported inside collections
- Unexpected extraneous bytes after + getCollectionName() + va
- Null value read when not allowed
- Not enough bytes to read a list
- Unexpected extraneous bytes after list value
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/06fe6c037634a0f0.
Report an issue: GitHub.