apache/cassandra · error · InvalidRequestException

Cannot specify as a CUSTOM option

Error message

Cannot specify %s as a CUSTOM option

What it means

When creating/altering a CUSTOM index, Cassandra reserves the internal option key `class_name` (IndexTarget.CUSTOM_INDEX_OPTION_NAME) for itself; it is set via the `USING` clause, not via OPTIONS. Supplying `class_name` inside the OPTIONS map is ambiguous and rejected with InvalidRequestException during IndexAttributes.validate().

Solutions

  1. Remove the 'class_name' key from the OPTIONS map
  2. Keep the index class only in the USING '<class>' clause

Example fix

// before
CREATE CUSTOM INDEX ON t (c) USING 'com.x.Idx' WITH OPTIONS = {'class_name': 'com.x.Idx'};
// after
CREATE CUSTOM INDEX ON t (c) USING 'com.x.Idx' WITH OPTIONS = {'mode': 'CONTAINS'};
Defensive patterns

Strategy: validation

Validate before calling

const opts = parseOptions(ddl);
if (opts.class_name !== undefined) throw new Error("Remove reserved key 'class_name' from OPTIONS; use USING clause");

Prevention

When it happens

Trigger: CREATE CUSTOM INDEX ... USING '...' WITH OPTIONS = {'class_name': '...'} — the reserved key appears in the raw options map.

Common situations: Migrating from Cassandra 2.x-era SASI/third-party DDL where class_name was spelled inside options; LLM/ORM-generated CQL duplicating the USING class into OPTIONS.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/statements/schema/IndexAttributes.java:60

    {
        keywords.add(KW_OPTIONS);
    }

    public void validate() throws RequestValidationException
    {
        validate(keywords, obsoleteKeywords);

        if (isCustom && customClass == null)
            throw new InvalidRequestException("CUSTOM index requires specifiying the index class");

        if (!isCustom && customClass != null)
            throw new InvalidRequestException("Cannot specify index class for a non-CUSTOM index");

        if (!isCustom && !properties.isEmpty())
            throw new InvalidRequestException("Cannot specify options for a non-CUSTOM index");

        if (getRawOptions().containsKey(IndexTarget.CUSTOM_INDEX_OPTION_NAME))
            throw new InvalidRequestException(String.format("Cannot specify %s as a CUSTOM option",
                                                            IndexTarget.CUSTOM_INDEX_OPTION_NAME));

        if (getRawOptions().containsKey(IndexTarget.TARGET_OPTION_NAME))
            throw new InvalidRequestException(String.format("Cannot specify %s as a CUSTOM option",
                                                            IndexTarget.TARGET_OPTION_NAME));

    }

    private Map<String, String> getRawOptions() throws SyntaxException
    {
        Map<String, String> options = getMap(KW_OPTIONS);
        return options == null ? Collections.emptyMap() : options;
    }

    public Map<String, String> getOptions() throws SyntaxException
    {
        Map<String, String> options = new HashMap<>(getRawOptions());
        options.put(IndexTarget.CUSTOM_INDEX_OPTION_NAME, customClass);

View on GitHub (pinned to 88fd0f6a0e)