apache/cassandra · critical · ConfigurationException

num_tokens must be >= 1

Error message

num_tokens must be >= 1

What it means

BootStrapper.getBootstrapTokens reads num_tokens from DatabaseDescriptor; if configured below 1 the bootstrap cannot allocate any tokens and throws ConfigurationException. This validates cassandra.yaml's num_tokens before token allocation begins.

Source

Thrown at src/java/org/apache/cassandra/dht/BootStrapper.java:239

    public static Collection<Token> getBootstrapTokens(final ClusterMetadata metadata, InetAddressAndPort address) throws ConfigurationException
    {
        String allocationKeyspace = DatabaseDescriptor.getAllocateTokensForKeyspace();
        Integer allocationLocalRf = DatabaseDescriptor.getAllocateTokensForLocalRf();
        Collection<String> initialTokens = DatabaseDescriptor.getInitialTokens();
        if (initialTokens.size() > 0 && allocationKeyspace != null)
            logger.warn("manually specified tokens override automatic allocation");

        // if user specified tokens, use those
        if (initialTokens.size() > 0)
        {
            Collection<Token> tokens = getSpecifiedTokens(metadata, initialTokens);
            BootstrapDiagnostics.useSpecifiedTokens(address, allocationKeyspace, tokens, DatabaseDescriptor.getNumTokens());
            return tokens;
        }

        int numTokens = DatabaseDescriptor.getNumTokens();
        if (numTokens < 1)
            throw new ConfigurationException("num_tokens must be >= 1");

        if (allocationKeyspace != null)
            return allocateTokens(metadata, address, allocationKeyspace, numTokens);

        if (allocationLocalRf != null)
            return allocateTokens(metadata, address, allocationLocalRf, numTokens);

        if (numTokens == 1)
            logger.warn("Picking random token for a single vnode.  You should probably add more vnodes and/or use the automatic token allocation mechanism.");

        Collection<Token> tokens = getRandomTokens(metadata, numTokens);
        BootstrapDiagnostics.useRandomTokens(address, metadata, numTokens, tokens);
        return tokens;
    }

    private static Collection<Token> getSpecifiedTokens(final ClusterMetadata metadata,
                                                        Collection<String> initialTokens)
    {

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Set num_tokens to a positive integer (default 16 in modern versions, 1 for single-token-per-node deployments) in cassandra.yaml and restart bootstrap.
  2. Check for environment/config templating that substituted 0 (e.g. ${NUM_TOKENS} defaulting empty->0).
  3. If using the legacy initial_token path, num_tokens must still be >= 1; ensure it is not disabled via a broken override.
  4. Validate the config before startup with a config-check or by inspecting effective values in the logs.

Example fix

// cassandra.yaml before
num_tokens: 0
// after
num_tokens: 16
Defensive patterns

Strategy: validation

Validate before calling

// Before startup/bootstrap
int numTokens = Integer.parseInt(config.getOrDefault("num_tokens", "16"));
if (numTokens < 1)
    throw new IllegalArgumentException("num_tokens must be >= 1, got " + numTokens);

Try / catch

try { node.bootstrap(); }
catch (ConfigurationException e) {
    if (e.getMessage().contains("num_tokens must be >= 1"))
        // fix cassandra.yaml and restart
}

Prevention

When it happens

Trigger: Starting a node to bootstrap with num_tokens set to 0 or a negative value in cassandra.yaml (or via system property override).

Common situations: Hand-edited cassandra.yaml with num_tokens: 0; scripted config generation that computed 0 tokens; copying config templates with placeholders left unexpanded; confusion between num_tokens and allocate_tokens_for_local_replication_factor.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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