{"record":{"id":"5317e8b5a5904d60","repo":"microsoft/garnet","slug":"incompatible-clusterconfig-version-expected-clus","errorCode":null,"errorMessage":"Incompatible ClusterConfig version: expected {ClusterConfigVersion}, got {version}","messagePattern":"Incompatible ClusterConfig version: expected (.+?), got (.+?)","errorType":"exception","errorClass":"InvalidDataException","httpStatus":null,"severity":"error","filePath":"libs/cluster/Server/ClusterConfigSerializer.cs","lineNumber":137,"sourceCode":"            ms.Position = segmentCountPosition;\n            writer.Write(segmentCount);\n            ms.Position = _position;\n        }\n\n        /// <summary>\n        /// Deserialize config from byte array\n        /// </summary>\n        public static ClusterConfig FromByteArray(byte[] other)\n        {\n            var ms = new MemoryStream(other);\n            var reader = new BinaryReader(ms);\n\n            // Read and validate serialization format version\n            if (other.Length < 1)\n                throw new InvalidDataException(\"Invalid ClusterConfig payload: too short to contain a version\");\n            var version = reader.ReadByte();\n            if (version != ClusterConfigVersion)\n                throw new InvalidDataException($\"Incompatible ClusterConfig version: expected {ClusterConfigVersion}, got {version}\");\n\n            var newSlotMap = DeserializeSlotMap(ref reader);\n\n            int numWorkers = reader.ReadInt32();\n            var newWorkers = new Worker[numWorkers];\n            for (int i = 1; i < numWorkers; i++)\n            {\n                newWorkers[i].Nodeid = reader.ReadString();\n                newWorkers[i].Address = reader.ReadString();\n                newWorkers[i].Port = reader.ReadInt32();\n                newWorkers[i].ConfigEpoch = reader.ReadInt64();\n                newWorkers[i].Role = (NodeRole)reader.ReadByte();\n\n                byte isNull = reader.ReadByte();\n                if (isNull > 0)\n                    newWorkers[i].ReplicaOfNodeId = reader.ReadString();\n\n                newWorkers[i].ReplicationOffset = reader.ReadInt64();","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/cluster/Server/ClusterConfigSerializer.cs#L119-L155","documentation":"After the length check, FromByteArray reads one version byte and compares it to ClusterConfigVersion (currently 1). A mismatch throws InvalidDataException with both expected and observed versions. This enforces binary compatibility of the gossip/replication config format across nodes — a node running a different Garnet build cannot join a cluster whose peers serialize a different config version.","triggerScenarios":"Two Garnet nodes with different ClusterConfig serialization versions exchange gossip or replicate a config; the receiver sees a version byte it does not understand. Also any caller deserializing a config produced by a different/older/newer build.","commonSituations":"Rolling upgrade where nodes run mixed Garnet versions during the transition; a config blob persisted by an older version loaded by a newer one; dev/test cluster with mismatched builds; cross-major-version incompatibility.","solutions":["Run the same Garnet version (and thus the same ClusterConfigVersion) on all cluster nodes.","During rolling upgrades, follow the documented upgrade order so config versions stay compatible across the transition.","If loading a persisted config, regenerate it with the current build or migrate it to the supported version."],"exampleFix":"// before — mismatched versions across nodes\nnode-A (v1.0, ClusterConfigVersion=1)  <--gossip-->  node-B (v2.0, ClusterConfigVersion=2)\n\n// after — align all nodes to one Garnet version\n// upgrade node-A to v2.0 so both serialize ClusterConfigVersion=2","handlingStrategy":"validation","validationCode":"// Peek the version without full deserialization to reject incompatible payloads early\nif (!ClusterConfig.TryPeekVersion(payload, out var v) || v != ClusterConfig.ClusterConfigVersion)\n    logger?.LogWarning(\"incompatible cluster config version {V}\", v);","typeGuard":"bool IsCompatibleVersion(byte[] p) => ClusterConfig.TryPeekVersion(p, out var v) && v == ClusterConfig.ClusterConfigVersion;","tryCatchPattern":"try { var config = ClusterConfig.FromByteArray(payload); }\ncatch (InvalidDataException ex) when (ex.Message.Contains(\"version\")) { /* peer runs a different Garnet build; skip */ }","preventionTips":["Run the same Garnet version on all cluster nodes so ClusterConfigVersion matches.","Follow the documented rolling-upgrade order to keep config versions compatible.","Regenerate persisted configs with the current build instead of loading old ones."],"tags":["csharp","cluster-config","version-mismatch","deserialization","cluster","gossip"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}