apache/cassandra · error · IllegalStateException

Unhandled domain

Error message

Unhandled domain {domain}

What it means

TxnRead.empty() returns the singleton empty read for the given Domain. The switch handles Key and Range and places the throw in the default branch, so any other/unrecognized Domain value throws IllegalStateException. It is an internal exhaustiveness guard.

Solutions

  1. Add a case for the new Domain constant returning an appropriate empty TxnRead
  2. Ensure createTxnRead only calls empty() with Key or Range domains
  3. Check for version skew across the cluster

Example fix

// before
default:
    throw new IllegalStateException("Unhandled domain " + domain);
// after
case Range:
    return EMPTY_RANGE;
default:
    throw new IllegalStateException("Unhandled domain " + domain);
Defensive patterns

Strategy: validation

Validate before calling

if (domain != Domain.Key && domain != Domain.Range)
    throw new IllegalArgumentException("TxnRead.empty only supports Key or Range, got " + domain);

Type guard

static boolean isEmptySupported(Domain domain) {
    return domain == Domain.Key || domain == Domain.Range;
}

Try / catch

try { TxnRead r = TxnRead.empty(domain); }
catch (IllegalStateException e) { /* unknown domain — inspect createTxnRead inputs */ }

Prevention

When it happens

Trigger: Calling TxnRead.empty(domain) with a Domain other than Key or Range — e.g. from createTxnRead when the txn's seekables domain is a newly added or corrupted value.

Common situations: Adding a new Domain enum constant without updating TxnRead; deserialization of a transaction from a node running different code; logic errors in createTxnRead deriving the domain.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/service/accord/txn/TxnRead.java:96

import static org.apache.cassandra.utils.NullableSerializer.serializeNullable;
import static org.apache.cassandra.utils.NullableSerializer.serializedNullableSize;

public class TxnRead extends AbstractKeySorted<TxnNamedRead> implements Read
{
    private static final TxnRead EMPTY_KEY = new TxnRead(TableMetadatas.none(), Domain.Key);
    private static final TxnRead EMPTY_RANGE = new TxnRead(TableMetadatas.none(), Domain.Range);
    private static final long EMPTY_SIZE = ObjectSizes.measure(EMPTY_KEY);
    private static final Comparator<TxnNamedRead> TXN_NAMED_READ_KEY_COMPARATOR = Comparator.comparing(a -> ((PartitionKey) a.key()));
    private static final byte TYPE_EMPTY_KEY = 0;
    private static final byte TYPE_EMPTY_RANGE = 1;
    private static final byte TYPE_NOT_EMPTY = 2;

    public static TxnRead empty(Domain domain)
    {
        switch (domain)
        {
            default:
                throw new IllegalStateException("Unhandled domain " + domain);
            case Key:
                return EMPTY_KEY;
            case Range:
                return EMPTY_RANGE;
        }
    }

    final TableMetadatas tables;
    // Cassandra's consistency level used by Accord to safely read data written outside of Accord
    @Nullable
    private final ConsistencyLevel cassandraConsistencyLevel;

    // Specifies the domain in case the TxnRead is empty and it can't be inferred
    private final Domain domain;

    private TxnRead(TableMetadatas tables, Domain domain)
    {
        super(new TxnNamedRead[0], domain);

View on GitHub (pinned to 88fd0f6a0e)