{"record":{"id":"613be77a0122b95d","repo":"apache/cassandra","slug":"seeds-list-is-now-empty","errorCode":null,"errorMessage":"Seeds list is now empty!","messagePattern":"Seeds list is now empty!","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/java/org/apache/cassandra/gms/Gossiper.java","lineNumber":696,"sourceCode":"    }\n\n    /**\n     * Removes the endpoint from Gossip but retains endpoint state\n     */\n    public void removeEndpoint(InetAddressAndPort endpoint)\n    {\n        checkProperThreadForStateMutation();\n        // do subscribers first so anything in the subscriber that depends on gossiper state won't get confused\n        for (IEndpointStateChangeSubscriber subscriber : subscribers)\n            subscriber.onRemove(endpoint);\n\n        if(seeds.contains(endpoint))\n        {\n            buildSeedsList();\n            seeds.remove(endpoint);\n            logger.info(\"removed {} from seeds, updated seeds list = {}\", endpoint, seeds);\n            if (seeds.isEmpty())\n                logger.warn(\"Seeds list is now empty!\");\n        }\n\n        inflightEcho.remove(endpoint);\n        if (disableEndpointRemoval)\n            return;\n\n        liveEndpoints.remove(endpoint);\n        unreachableEndpoints.remove(endpoint);\n        MessagingService.instance().versions.reset(endpoint);\n        quarantineEndpoint(endpoint);\n        MessagingService.instance().closeOutbound(endpoint);\n        MessagingService.instance().removeInbound(endpoint);\n        logger.debug(\"removing endpoint {}\", endpoint);\n        GossiperDiagnostics.removedEndpoint(this, endpoint);\n    }\n\n    @VisibleForTesting\n    public void unsafeAnnulEndpoint(InetAddressAndPort endpoint)","sourceCodeStart":678,"sourceCodeEnd":714,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/gms/Gossiper.java#L678-L714","documentation":"When an endpoint is removed from gossip via removeEndpoint and it was a seed, Gossiper rebuilds the seeds list and removes the endpoint. If no seeds remain it logs a warning — not an exception — because a cluster with an empty seed list cannot bootstrap new nodes and gossip convergence is at risk.","triggerScenarios":"removeEndpoint (via unsafeAnnulEndpoint or doStatusCheck eviction) removes the last seed from the configured seed list, leaving seeds empty after buildSeedsList().","commonSituations":" assassinating/decommissioning every seed node in a small cluster; misconfigured cassandra.yaml where all seeds point at one node that is removed; accidental evictIfExpired of a single-seed dev cluster.","solutions":["Restore at least one seed: re-add a seed node or fix cassandra.yaml seed_provider list and restart.","Ensure the cluster keeps at least one seed (recommendation: one seed per DC, never zero).","If the node was intentionally removed, update all nodes' seed configs to point at surviving nodes.","If caused by accidental eviction, restart gossip or use nodetool to re-add the endpoint."],"exampleFix":"// before (cassandra.yaml)\nseed_provider:\n  - seeds: \"10.0.0.1\"   # only seed, then removed\n// after\nseed_provider:\n  - seeds: \"10.0.0.1,10.0.0.2\"  # multiple seeds across DCs","handlingStrategy":"validation","validationCode":"if (getSeeds().isEmpty()) throw new ConfigurationException(\"Cluster must retain at least one seed\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always keep >=1 (ideally >=2) seeds per datacenter in cassandra.yaml.","Never decommission/assassinate all seeds simultaneously; add a new seed before removing one.","Audit seed config on all nodes after topology changes."],"tags":["cassandra","gossip","seeds","configuration"],"backgroundTag":"empty-seed-list","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}