{"record":{"id":"4587ce2049a6a0fd","repo":"apache/cassandra","slug":"extracting-tokens-from-s-sequence-is-neither-nece","errorCode":null,"errorMessage":"Extracting tokens from %s sequence is neither necessary nor supported here","messagePattern":"Extracting tokens from (.+?) sequence is neither necessary nor supported here","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/tcm/compatibility/GossipHelper.java","lineNumber":208,"sourceCode":"\n    public static Collection<Token> getTokensFromOperation(NodeId nodeId, ClusterMetadata metadata)\n    {\n        return getTokensFromOperation(metadata.inProgressSequences.get(nodeId));\n    }\n\n    public static Collection<Token> getTokensFromOperation(MultiStepOperation<?> sequence)\n    {\n        if (null == sequence)\n            return Collections.emptySet();\n\n        if (sequence.kind() == MultiStepOperation.Kind.JOIN)\n            return new HashSet<>(((BootstrapAndJoin)sequence).finishJoin.tokens);\n        else if (sequence.kind() == MultiStepOperation.Kind.REPLACE)\n            return new HashSet<>(((BootstrapAndReplace)sequence).bootstrapTokens);\n        else if (sequence.kind() == MultiStepOperation.Kind.MOVE)\n            return new HashSet<>(((Move)sequence).tokens);\n\n        throw new IllegalArgumentException(String.format(\"Extracting tokens from %s sequence is neither necessary nor supported here\",\n                                                         sequence.kind()));\n    }\n\n    private static Collection<Token> getTokensIn(IPartitioner partitioner, EndpointState epState)\n    {\n        try\n        {\n            if (epState == null)\n                return Collections.emptyList();\n\n            VersionedValue versionedValue = epState.getApplicationState(TOKENS);\n            if (versionedValue == null)\n                return Collections.emptyList();\n\n            return TokenSerializer.deserialize(partitioner, new DataInputStream(new ByteArrayInputStream(versionedValue.toBytes())));\n        }\n        catch (IOException e)\n        {","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tcm/compatibility/GossipHelper.java#L190-L226","documentation":"GossipHelper.getTokensFromOperation extracts token collections only for bootstrap/replace/move multi-step operations; if invoked with any other operation kind it throws IllegalArgumentException because extracting tokens is meaningless there.","triggerScenarios":"Calling getTokensFromOperation with a MultiStepOperation whose kind is not BOOTSTRAP, REPLACE, or MOVE (e.g. a decommission/leave sequence) during the gossip-to-TCM upgrade translation.","commonSituations":"Upgrade path encountering a node mid-decommission or other operation type; code changes reusing this helper for new sequence kinds without extending it.","solutions":["Only call this helper for BOOTSTRAP/REPLACE/MOVE sequences; handle other kinds at the call site","Extend the method with a branch for the new operation kind if its tokens are genuinely needed","Skip token extraction for the offending sequence during upgrade (it's typically not required)"],"exampleFix":"// before\nif (sequence.kind() == MultiStepOperation.Kind.LEAVE)\n    return getTokensFromOperation(nodeId, metadata); // throws\n// after\nif (sequence.kind() == MultiStepOperation.Kind.LEAVE)\n    return Collections.emptySet(); // tokens not needed for LEAVE","handlingStrategy":"type-guard","validationCode":"if (kind != MultiStepOperation.Kind.BOOTSTRAP\n && kind != MultiStepOperation.Kind.REPLACE\n && kind != MultiStepOperation.Kind.MOVE)\n    return Collections.emptySet(); // tokens not needed here","typeGuard":"static boolean hasExtractableTokens(MultiStepOperation<?> seq) {\n    MultiStepOperation.Kind k = seq.kind();\n    return k == MultiStepOperation.Kind.BOOTSTRAP\n        || k == MultiStepOperation.Kind.REPLACE\n        || k == MultiStepOperation.Kind.MOVE;\n}","tryCatchPattern":"try { tokens = getTokensFromOperation(nodeId, metadata); }\ncatch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"neither necessary nor supported\")) tokens = Collections.emptySet();\n    else throw e;\n}","preventionTips":["Check sequence kind before extracting tokens","Extend the helper explicitly when new MultiStepOperation kinds are introduced"],"tags":["tcm","gossip","upgrade","tokens"],"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"}