apache/cassandra · critical · ConfigurationException

Fatal configuration error; unable to start server. See…

Error message

Fatal configuration error; unable to start server.  See log for stacktrace.

What it means

While instantiating the configured SeedProvider class, applySeedProvider() catches any exception from class loading or constructor invocation and rethrows a ConfigurationException whose message is '<cause message>\nFatal configuration error; unable to start server. See log for stacktrace.' — a startup-fatal wrapper indicating the seed provider could not be created.

Solutions

  1. Read the leading part of the message/log for the underlying cause (class not found vs constructor error)
  2. Set class_name to org.apache.cassandra.locator.SimpleSeedProvider (or fix the custom provider's deployment)
  3. Ensure any custom seed provider JAR is in lib/ on all nodes and its constructor accepts Map<String,String>
  4. Fix parameters (e.g. seeds string format host:port, comma-separated) in cassandra.yaml

Example fix

// cassandra.yaml before
seed_provider:
  - class_name: org.apache.cassandra.locator.SimpleSeedProviderTypo
    parameters:
      - seeds: "10.0.1.1"
// after
seed_provider:
  - class_name: org.apache.cassandra.locator.SimpleSeedProvider
    parameters:
      - seeds: "10.0.1.1:7000"
Defensive patterns

Strategy: try-catch

Validate before calling

String cls = conf.seed_provider.class_name;
try {
    Class<?> c = Class.forName(cls, false, DatabaseDescriptor.class.getClassLoader());
    c.getConstructor(Map.class);
} catch (Throwable t) { throw new IllegalStateException("Bad seed_provider class: " + t); }

Try / catch

try { DatabaseDescriptor.applySeedProvider(); } catch (ConfigurationException e) {
    String cause = e.getMessage().split("\\n")[0]; // underlying cause precedes the fatal-configuration suffix
}

Prevention

When it happens

Trigger: applySeedProvider() called with a seed_provider.class_name that cannot be loaded or constructed: misspelled FQCN, missing class (no such JAR), constructor not accepting Map, or constructor throwing (e.g. invalid parameters).

Common situations: Custom SeedProvider implementation not deployed on the node; typo in class_name; switching providers across Cassandra versions where constructor signatures changed; invalid seeds syntax causing provider-internal failure.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/config/DatabaseDescriptor.java:1675

    }

    public static void applySeedProvider()
    {
        // load the seeds for node contact points
        if (conf.seed_provider == null)
        {
            throw new ConfigurationException("seeds configuration is missing; a minimum of one seed is required.", false);
        }
        try
        {
            Class<? extends SeedProvider> seedProviderClass =
                FBUtilities.classForNameWithoutInitialization(conf.seed_provider.class_name, "seed provider", SeedProvider.class);
            seedProvider = (SeedProvider) seedProviderClass.getConstructor(Map.class).newInstance(conf.seed_provider.parameters);
        }
        // there are about 5 checked exceptions that could be thrown here.
        catch (Exception e)
        {
            throw new ConfigurationException(e.getMessage() + "\nFatal configuration error; unable to start server.  See log for stacktrace.", true);
        }
        if (seedProvider.getSeeds().size() == 0)
            throw new ConfigurationException("The seed provider lists no seeds.", false);
    }

    @VisibleForTesting
    static void checkForLowestAcceptedTimeouts(Config conf)
    {
        if (conf.read_request_timeout.toMilliseconds() < LOWEST_ACCEPTED_TIMEOUT.toMilliseconds())
        {
            logInfo("read_request_timeout", conf.read_request_timeout, LOWEST_ACCEPTED_TIMEOUT);
            conf.read_request_timeout = new DurationSpec.LongMillisecondsBound("10ms");
        }

        if (conf.range_request_timeout.toMilliseconds() < LOWEST_ACCEPTED_TIMEOUT.toMilliseconds())
        {
            logInfo("range_request_timeout", conf.range_request_timeout, LOWEST_ACCEPTED_TIMEOUT);
            conf.range_request_timeout = new DurationSpec.LongMillisecondsBound("10ms");

View on GitHub (pinned to 88fd0f6a0e)