{"record":{"id":"781e2e08d0066bd6","repo":"apache/cassandra","slug":"received-a-command-with-the-thrift-flag-set-this","errorCode":null,"errorMessage":"Received a command with the thrift flag set. This means thrift is in use in a mixed 3.0/3.X and 4.0+ cluster, which is unsupported. Make sure to stop using thrift before upgrading to 4.0","messagePattern":"Received a command with the thrift flag set\\. This means thrift is in use in a mixed 3\\.0/3\\.X and 4\\.0\\+ cluster, which is unsupported\\. Make sure to stop using thrift before upgrading to 4\\.0","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"src/java/org/apache/cassandra/db/ReadCommand.java","lineNumber":1465,"sourceCode":"            if (hasIndex)\n            {\n                IndexMetadata index = deserializeIndexMetadata(in, version, tableMetadata);\n                Index.Group indexGroup =  Keyspace.openAndGetStore(tableMetadata).indexManager.getIndexGroup(index);\n                if (indexGroup != null)\n                    indexQueryPlan = indexGroup.queryPlanFor(rowFilter);\n            }\n\n            return deserializer.deserialize(in, version, schemaVersion, isDigest, digestVersion, acceptsTransient, potentialTxnConflicts, tableMetadata, nowInSec, columnFilter, rowFilter, limits, indexQueryPlan);\n        }\n\n        public ReadCommand deserialize(DataInputPlus in, int version) throws IOException\n        {\n            Kind kind = Kind.fromOrdinal(in.readByte());\n            int flags = in.readByte();\n            // Shouldn't happen or it's a user error (see comment above) but\n            // better complain loudly than doing the wrong thing.\n            if (isForThrift(flags))\n                throw new IllegalStateException(\"Received a command with the thrift flag set. \"\n                                                + \"This means thrift is in use in a mixed 3.0/3.X and 4.0+ cluster, \"\n                                                + \"which is unsupported. Make sure to stop using thrift before \"\n                                                + \"upgrading to 4.0\");\n\n            int digestVersion = isDigest(flags) ? in.readUnsignedVInt32() : 0;\n            TableId tableId = TableId.deserialize(in);\n\n            Epoch schemaVersion = Epoch.EMPTY;\n            if (version >= MessagingService.VERSION_60)\n                schemaVersion = Epoch.serializer.deserialize(in);\n            TableMetadata tableMetadata;\n            try\n            {\n                tableMetadata = schema.getExistingTableMetadata(tableId);\n            }\n            catch (UnknownTableException e)\n            {\n                ClusterMetadata metadata = ClusterMetadata.current();","sourceCodeStart":1447,"sourceCodeEnd":1483,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/db/ReadCommand.java#L1447-L1483","documentation":"ReadCommand's serializer for messages from pre-4.0 (3.0/3.X) nodes throws IllegalStateException when the deserialized command has the thrift 'forThrift' flag set. Thrift was removed in 4.0; seeing this flag means an unsupported mixed-version cluster is still issuing Thrift-originated reads, and proceeding would silently do the wrong thing.","triggerScenarios":"Rolling upgrade of a 3.0/3.X cluster to 4.0+ while some application or node still uses the Thrift protocol; an old node serializing a read command flagged for Thrift that a 4.0+ node tries to deserialize.","commonSituations":"Mixed 3.x/4.0 clusters during upgrade where legacy Thrift clients were never migrated to CQL; forgotten legacy applications using the old thrift API; upgrade runbooks that skipped the 'stop using thrift' prerequisite.","solutions":["Stop all Thrift clients and migrate them to CQL (the 4.0+ native protocol) before continuing the rolling upgrade.","Verify no nodes/clients use thrift: check start_rpc settings and application configs on 3.x nodes.","Complete the cluster upgrade so all nodes are 4.0+ (which rejects thrift entirely), keeping versions homogeneous.","If seen unexpectedly, check for stale 3.x nodes still joined to the cluster (nodetool status / describecluster)."],"exampleFix":"// before\n// legacy app on 3.x node using thrift client against mixed cluster\ncassandra.client.transport=THRIFT\n// after\ncqlSession = CqlSession.builder().addContactPoint(node).build(); // CQL 4 native protocol","handlingStrategy":"fallback","validationCode":"// Before upgrading: audit all clients for thrift usage.\n// On 3.x: grep start_rpc in cassandra.yaml; check netstat for port 9160 connections.","typeGuard":null,"tryCatchPattern":"try { deserialize(cmd); } catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"thrift flag\")) { alertOpsMixedVersionCluster(); haltUpgrade(); } else throw e;\n}","preventionTips":["Migrate all Thrift clients to CQL before starting any 3.x → 4.x upgrade.","Keep cluster versions homogeneous during rolling upgrades.","Check port 9160 (thrift) traffic during upgrades.","Document the upgrade prerequisite: thrift must be retired first."],"tags":["thrift","mixed-version-cluster","upgrade","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-17T15:17:12.973Z"}