{"record":{"id":"ca1a94497c9c2812","repo":"apache/cassandra","slug":"this-node-has-more-than-one-token-and-cannot-be-mo","errorCode":null,"errorMessage":"This node has more than one token and cannot be moved thusly.","messagePattern":"This node has more than one token and cannot be moved thusly\\.","errorType":"exception","errorClass":"java.lang.UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/tcm/sequences/SingleNodeSequences.java","lineNumber":187,"sourceCode":"    static void move(Token newToken)\n    {\n        if (ClusterMetadataService.instance().isMigrating() || ClusterMetadataService.state() == ClusterMetadataService.State.GOSSIP)\n            throw new IllegalStateException(\"This cluster is migrating to cluster metadata, can't move until that is done.\");\n\n        if (newToken == null)\n            throw new IllegalArgumentException(\"Can't move to the undefined (null) token.\");\n\n        if (ClusterMetadata.current().tokenMap.tokens().contains(newToken))\n            throw new IllegalArgumentException(String.format(\"target token %s is already owned by another node.\", newToken));\n\n        // address of the current node\n        ClusterMetadata metadata = ClusterMetadata.current();\n        NodeId self = metadata.myNodeId();\n        // This doesn't make any sense in a vnodes environment.\n        if (metadata.tokenMap.tokens(self).size() > 1)\n        {\n            logger.error(\"Invalid request to move(Token); This node has more than one token and cannot be moved thusly.\");\n            throw new UnsupportedOperationException(\"This node has more than one token and cannot be moved thusly.\");\n        }\n\n        ClusterMetadataService.instance().commit(new PrepareMove(self,\n                                                                 Collections.singleton(newToken),\n                                                                 ClusterMetadataService.instance().placementProvider(),\n                                                                 true),\n                                                 m -> m,\n                                                 failureHandler(\"PrepareMove\", StorageService.instance::markMoveFailed));\n        InProgressSequences.finishInProgressSequences(self);\n\n        if (logger.isDebugEnabled())\n            logger.debug(\"Successfully moved to new token {}\", StorageService.instance.getLocalTokens().iterator().next());\n    }\n\n    private static ClusterMetadataService.CommitFailureHandler<ClusterMetadata> failureHandler(String type, Runnable markFailed)\n    {\n        return (code, msg) -> {\n            logger.warn(\"Got failure committing {} transformation: {} {}\", type, code, msg);","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tcm/sequences/SingleNodeSequences.java#L169-L205","documentation":"move(Token) only supports single-token (non-vnode) nodes. If the local node currently owns more than one token, moving 'the' token is ambiguous, so UnsupportedOperationException is thrown after logging the invalid request.","triggerScenarios":"Calling `nodetool move` on a node configured with num_tokens > 1 (vnodes) - metadata.tokenMap.tokens(self).size() > 1 - so the single-target move cannot be expressed.","commonSituations":"Operators accustomed to old single-token clusters running move on modern vnode-enabled nodes; attempting to rebalance a vnode node with nodetool move instead of cleanup/decommission+rebootstrap.","solutions":["Do not use move on vnode nodes; rebalance by decommissioning and re-bootstrapping with adjusted initial tokens, or use a rebalancing tool.","If single-token operation is truly required, redeploy the node with num_tokens=1 and a chosen initial_token.","Use `nodetool cleanup` after ownership changes rather than trying to move tokens."],"exampleFix":"// before\nnodetool move <token>                    // fails on vnode node\n// after\nnodetool decommission && rebootstrap with desired initial_token (or manage vnodes via num_tokens)","handlingStrategy":"validation","validationCode":"if (ClusterMetadata.current().tokenMap.tokens(self).size() > 1)\n    throw new UnsupportedOperationException(\"move is not supported for vnode nodes\");","typeGuard":"boolean isSingleTokenNode(NodeId self) { return ClusterMetadata.current().tokenMap.tokens(self).size() == 1; }","tryCatchPattern":"try { move(token); }\ncatch (UnsupportedOperationException e) { if (e.getMessage().contains(\"more than one token\")) { rebalanceViaBootstrap(); } else throw e; }","preventionTips":["Only use nodetool move on num_tokens=1 nodes","Rebalance vnode clusters via decommission/rebootstrap or tooling","Document vnode topology procedures for operators"],"tags":["cassandra","vnodes","topology","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}