{"record":{"id":"6342cc40d720add0","repo":"apache/cassandra","slug":"unable-to-start-s-because-the-node-is-not-in-the","errorCode":null,"errorMessage":"Unable to start %s because the node is not in the normal state.","messagePattern":"Unable to start (.+?) because the node is not in the normal state\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/service/StorageService.java","lineNumber":4163,"sourceCode":"        return postShutdownHooks.remove(hook);\n    }\n\n    /**\n     * Some services are shutdown during draining and we should not attempt to start them again.\n     *\n     * @param service - the name of the service we are trying to start.\n     * @throws IllegalStateException - an exception that nodetool is able to convert into a message to display to the user\n     */\n    synchronized void checkServiceAllowedToStart(String service)\n    {\n        if (isDraining()) // when draining isShutdown is also true, so we check first to return a more accurate message\n            throw new IllegalStateException(String.format(\"Unable to start %s because the node is draining.\", service));\n\n        if (isShutdown()) // do not rely on operationMode in case it gets changed to decommissioned or other\n            throw new IllegalStateException(String.format(\"Unable to start %s because the node was drained.\", service));\n\n        if (!isNormal() && joinRing) // if the node is not joining the ring, it is gossipping-only member which is in STARTING state forever\n            throw new IllegalStateException(String.format(\"Unable to start %s because the node is not in the normal state.\", service));\n    }\n\n    // Never ever do this at home. Used by tests.\n    @VisibleForTesting\n    public IPartitioner setPartitionerUnsafe(IPartitioner newPartitioner)\n    {\n        checkNotNull(newPartitioner, \"newPartitioner is null\");\n        checkState(originalPartitioner == null, \"Already changed the partitioner without resetting\");\n        originalPartitioner = DatabaseDescriptor.setPartitionerUnsafe(newPartitioner);\n        valueFactory = new VersionedValue.VersionedValueFactory(newPartitioner);\n        return originalPartitioner;\n    }\n\n    @VisibleForTesting\n    public void resetPartitionerUnsafe()\n    {\n        checkState(originalPartitioner != null, \"Original partitioner was never changed\");\n        DatabaseDescriptor.setPartitionerUnsafe(originalPartitioner);","sourceCodeStart":4145,"sourceCodeEnd":4181,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/service/StorageService.java#L4145-L4181","documentation":"checkServiceAllowedToStart(service) requires the node to be in NORMAL mode before starting services, but only when joinRing is true. If the node hasn't finished joining the ring (it stays in STARTING or another non-normal mode), starting the service is refused because a gossip-only/non-joined node shouldn't serve clients. Thrown as IllegalStateException for nodetool display.","triggerScenarios":"Starting native/rpc transport while the node is still bootstrapping, joining, or otherwise not NORMAL (e.g. calling startRPCServer early at startup, or a node stuck bootstrapping with join_ring=true).","commonSituations":"Custom startup scripts starting transport before the node joins the ring; nodes stuck in STARTING due to failed bootstrap/schema disagreement; join_ring misconfiguration.","solutions":["Wait for the node to reach NORMAL (log line 'Node / state jump to normal' or `nodetool status`) before starting services","If bootstrap failed, fix the cause (schema disagreement, streaming failure) and restart the node","Set join_ring=false only if you intend a gossip-only coordinator; the check is skipped in that case","Check system.log for bootstrap/streaming errors blocking the transition to NORMAL"],"exampleFix":"// before: start transport immediately at boot\nstorageService.startNativeTransport();\n// after: start only once the node is in NORMAL mode\nif (storageService.isNormal())\n    storageService.startNativeTransport();","handlingStrategy":"validation","validationCode":"StorageServiceMBean ss = ...;\nif (!ss.getOperationMode().equals(\"NORMAL\")) {\n    throw new IllegalStateException(\"wait for node to join ring before starting services\");\n}","typeGuard":"boolean canStartServices(StorageServiceMBean ss) {\n    return ss.getOperationMode().equals(\"NORMAL\") || !ss.isJoined(); // join_ring=false nodes skip check\n}","tryCatchPattern":"try { startNativeTransport(); } catch (IllegalStateException e) { if (e.getMessage().contains(\"not in the normal state\")) { retryWithBackoffAfterJoin(); } else { throw e; } }","preventionTips":["Wait for 'state jump to normal' log line before enabling services","Monitor bootstrap completion rather than process liveness","Fix any bootstrap failures (schema disagreement, streaming errors) before restarting services"],"tags":["bootstrap","node-lifecycle","startup"],"backgroundTag":"invalid-state-transition","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"}