apache/cassandra · error · ConfigurationException

Required option missing for index

Error message

Required option missing for index %s : %s

What it means

For CUSTOM indexes, IndexMetadata.validate requires the 'class_name' option (IndexTarget.CUSTOM_INDEX_OPTION_NAME) in the index options map so it can load the custom Index implementation class. Missing 'class_name' means Cassandra has no implementation to instantiate.

Solutions

  1. Add OPTIONS = {'class_name': 'com.example.YourIndex'} to the CREATE CUSTOM INDEX statement
  2. Ensure programmatic builders put IndexTarget.CUSTOM_INDEX_OPTION_NAME in the options map
  3. Use a non-CUSTOM index kind if you do not have a custom indexer class

Example fix

// before
CREATE CUSTOM INDEX my_idx ON ks.t (col); // no options
// after
CREATE CUSTOM INDEX my_idx ON ks.t (col) USING 'org.apache.cassandra.index.sasi.SASIIndex' WITH OPTIONS = {'mode': 'CONTAINS'};
Defensive patterns

Strategy: validation

Validate before calling

if (kind == Kind.CUSTOM && (options == null || !options.containsKey("class_name"))) throw new IllegalArgumentException("custom index requires class_name option");

Try / catch

try { index.validate(table); } catch (ConfigurationException e) { log.error("custom index missing class_name", e); }

Prevention

When it happens

Trigger: Creating a custom index without 'class_name' in the OPTIONS map (or with options null), then validate(TableMetadata) is called during schema creation.

Common situations: CREATE CUSTOM INDEX without the OPTIONS = {'class_name': '...'} clause; tooling that builds custom IndexMetadata but drops the options map.

Understand the failure class

Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/schema/IndexMetadata.java:145

    public static String generateDefaultIndexName(String table)
    {
        return PATTERN_NON_WORD_CHAR.matcher(table + "_idx").replaceAll("");
    }

    public void validate(TableMetadata table)
    {
        // TODO: address validating the length by CASSANDRA-20445
        if (!isValidCharsName(name))
            throw new ConfigurationException("Illegal index name " + name);

        if (kind == null)
            throw new ConfigurationException("Index kind is null for index " + name);

        if (kind == Kind.CUSTOM)
        {
            if (options == null || !options.containsKey(IndexTarget.CUSTOM_INDEX_OPTION_NAME))
                throw new ConfigurationException(String.format("Required option missing for index %s : %s",
                                                               name, IndexTarget.CUSTOM_INDEX_OPTION_NAME));

            // Get the fully qualified class name:
            String className = getIndexClassName();

            Class<? extends Index> indexerClass = FBUtilities.classForNameWithoutInitialization(className, "custom indexer", Index.class);
            validateCustomIndexOptions(table, indexerClass, options);
        }
    }

    public String getIndexClassName()
    {
        if (isCustom())
        {
            String className = options.get(IndexTarget.CUSTOM_INDEX_OPTION_NAME);
            return indexNameAliases.getOrDefault(toLowerCaseLocalized(className), className);
        }
        return CassandraIndex.class.getName();

View on GitHub (pinned to 88fd0f6a0e)