apache/cassandra · warning

Booting with ClusterMetadata from file:

Error message

Booting with ClusterMetadata from file: 

What it means

StartupMode.get selects how a node boots its cluster metadata. When the TCM_UNSAFE_BOOT_WITH_CLUSTERMETADATA system property is present, it logs a warning that the node will boot with a ClusterMetadata read from the given file and returns BOOT_WITH_CLUSTERMETADATA, bypassing seed-based and epoch-based startup mode resolution.

Source

Thrown at src/java/org/apache/cassandra/tcm/Startup.java:797

         * Node is starting for the first time, and should attempt to either discover existing CMS, or
         * participate in the leader election to establish a new one.
         */
        VOTE,
        /**
         * Node is starting for the first time, and is a designated first CMS node and can become a first CMS
         * node upon boot.
         */
        FIRST_CMS,
        /**
         * Node has to pick Cluster Metadata from the specified file. Used for testing and for (improbable) disaster recovery.
         */
        BOOT_WITH_CLUSTERMETADATA;

        static StartupMode get(Set<InetAddressAndPort> seeds)
        {
            if (CassandraRelevantProperties.TCM_UNSAFE_BOOT_WITH_CLUSTERMETADATA.isPresent())
            {
                logger.warn("Booting with ClusterMetadata from file: " + CassandraRelevantProperties.TCM_UNSAFE_BOOT_WITH_CLUSTERMETADATA.getString());
                return BOOT_WITH_CLUSTERMETADATA;
            }
            if (seeds.isEmpty())
                throw new IllegalArgumentException("Can not initialize CMS without any seeds");
            boolean hasAnyEpoch = SystemKeyspaceStorage.hasAnyEpoch();

            // For CCM and local dev clusters
            boolean isOnlySeed = DatabaseDescriptor.getSeeds().size() == 1
                                 && DatabaseDescriptor.getSeeds().contains(FBUtilities.getBroadcastAddressAndPort())
                                 && DatabaseDescriptor.getSeeds().iterator().next().getAddress().isLoopbackAddress();
            boolean hasBootedBefore = SystemKeyspace.getLocalHostId() != null;
            logger.info("hasAnyEpoch = {}, hasBootedBefore = {}", hasAnyEpoch, hasBootedBefore);
            if (!hasAnyEpoch && hasBootedBefore &&
                // Atomic long processor currently does not support upgrades
                !CassandraRelevantProperties.TCM_USE_ATOMIC_LONG_PROCESSOR.getBoolean())
                return UPGRADE;
            else if (hasAnyEpoch)
                return NORMAL;

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Verify the flag and file path are intentional; the node will trust that file's metadata wholesale.
  2. Sanity-check the file: it must be a serialized ClusterMetadata snapshot consistent with the node's host ID and tokens.
  3. Remove the property once recovery is complete so subsequent restarts use normal startup modes.
  4. Alternatively unset the property and rely on seeds plus SystemKeyspaceStorage.hasAnyEpoch() to pick UPGRADE or NORMAL modes.

Example fix

// before (cassandra-env.sh)
JVM_OPTS="$JVM_OPTS -Dcassandra.tcm_unsafe_boot_with_clustermetadata=/var/lib/cassandra/metadata.bin"
// after (recovery finished)
# property removed; normal startup applies
Defensive patterns

Strategy: validation

Validate before calling

// Verify the metadata file exists before selecting the mode
String f = CassandraRelevantProperties.TCM_UNSAFE_BOOT_WITH_CLUSTERMETADATA.getString();
if (f != null && !new File(f).exists()) {
    throw new IllegalArgumentException("ClusterMetadata file missing: " + f);
}

Prevention

When it happens

Trigger: Any node startup where -Dcassandra.tcm_unsafe_boot_with_clustermetadata=<file> is set on the JVM, regardless of seeds or existing epochs; get() checks that property first.

Common situations: Recovering a cluster whose CMS/TCM log was destroyed; staging metadata offline then booting from it; a leftover recovery flag in cassandra-env.sh reaching production.

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/e8d21fb87d7af656. Report an issue: GitHub.