apache/cassandra · critical · AssertionError

Invalid verb id + id + - we only allow ids between 0 and…

Error message

Invalid verb id + id + - we only allow ids between 0 and CUSTOM_VERB_START - MAX_CUSTOM_VERB_ID

What it means

For non-CUSTOM (built-in) verbs, the id must be in [0, CUSTOM_VERB_START - MAX_CUSTOM_VERB_ID] so built-in and custom id spaces never overlap. A too-large built-in id fails with AssertionError in the Verb constructor.

Solutions

  1. Assign the new built-in verb an id <= CUSTOM_VERB_START - MAX_CUSTOM_VERB_ID, keeping custom ids >= CUSTOM_VERB_START separate
  2. Review the Verb enum id allocation scheme before adding verbs
  3. Add a startup/test check that all ids are within bounds and non-overlapping

Example fix

// before
NEW_VERB(MESSAGES, CUSTOM_VERB_START - 1, ...)
// after
NEW_VERB(MESSAGES, CUSTOM_VERB_START - MAX_CUSTOM_VERB_ID - 1, ...) // inside built-in range
Defensive patterns

Strategy: validation

Validate before calling

if (kind != Verb.Kind.CUSTOM && id > Verb.CUSTOM_VERB_START - Verb.MAX_CUSTOM_VERB_ID) throw new IllegalArgumentException("built-in verb id out of range: " + id);

Prevention

When it happens

Trigger: Declaring a built-in Verb with id > CUSTOM_VERB_START - MAX_CUSTOM_VERB_ID, e.g. appending a new built-in verb with an id chosen carelessly at the end of the enum.

Common situations: Adding new built-in verbs in the Verb enum and using the next raw integer without checking the reserved custom range; merge conflicts that duplicate or bump ids.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/net/Verb.java:495

        this(kind, id, priority, expiration, stage, serializer, handler, null);
    }

    Verb(Kind kind, int id, Priority priority, ToLongFunction<TimeUnit> expiration, Stage stage, Supplier<? extends IVersionedAsymmetricSerializer<?, ?>> serializer, Supplier<? extends IVerbHandler<?>> handler, Verb responseVerb)
    {
        this.stage = stage;
        if (id < 0)
            throw new IllegalArgumentException("Verb id must be non-negative, got " + id + " for verb " + name());

        if (kind == CUSTOM)
        {
            if (id > MAX_CUSTOM_VERB_ID)
                throw new AssertionError("Invalid custom verb id " + id + " - we only allow custom ids between 0 and " + MAX_CUSTOM_VERB_ID);
            this.id = idForCustomVerb(id);
        }
        else
        {
            if (id > CUSTOM_VERB_START - MAX_CUSTOM_VERB_ID)
                throw new AssertionError("Invalid verb id " + id + " - we only allow ids between 0 and " + (CUSTOM_VERB_START - MAX_CUSTOM_VERB_ID));
            this.id = id;
        }
        this.priority = priority;
        this.serializer = serializer;
        this.handler = handler;
        this.responseVerb = responseVerb;
        this.expiration = expiration;
        this.kind = kind;
        // this is a little hacky, but reduces the number of parameters up top
        this.isResponse = name().endsWith("_RSP") || handler == RESPONSE_HANDLER;
    }

    public <In, Out> IVersionedAsymmetricSerializer<In, Out> serializer()
    {
        return (IVersionedAsymmetricSerializer<In, Out>) serializer.get();
    }

    public <T> IVerbHandler<T> handler()

View on GitHub (pinned to 88fd0f6a0e)