{"record":{"id":"72f0a990b0612b41","repo":"apache/cassandra","slug":"cannot-serialize-redundantstatus-larger-than-0xfff","errorCode":null,"errorMessage":"Cannot serialize RedundantStatus larger than 0xFFFF. Requires serialization changes.","messagePattern":"Cannot serialize RedundantStatus larger than 0xFFFF\\. Requires serialization changes\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/service/accord/serializers/CommandStoreSerializers.java","lineNumber":278,"sourceCode":"            if (b.endEpoch == Long.MAX_VALUE) out.writeUnsignedVInt(0L);\n            else out.writeUnsignedVInt(1 + b.endEpoch - b.startEpoch);\n            serializeNullable(b.staleUntilAtLeast, out);\n            out.writeUnsignedVInt32(b.bounds.length);\n            for (TxnId bound : b.bounds)\n            {\n                CommandSerializers.txnId.serialize(bound, out);\n            }\n            for (int i = 0 ; i < b.bounds.length ; ++i)\n            {\n                out.writeShort(cast(b.status(i * 2)));\n                out.writeShort(cast(b.status(i * 2 + 1)));\n            }\n        }\n\n        private short cast(long v)\n        {\n            if ((v & ~0xFFFF) != 0)\n                throw new IllegalStateException(\"Cannot serialize RedundantStatus larger than 0xFFFF. Requires serialization changes.\");\n            return (short)v;\n        }\n\n        @Override\n        public RedundantBefore.Bounds deserialize(DataInputPlus in) throws IOException\n        {\n            if (in.readByte() == 0)\n                return null;\n\n            Range range = KeySerializers.range.deserialize(in);\n            long startEpoch = in.readUnsignedVInt();\n            long endEpoch = in.readUnsignedVInt();\n            if (endEpoch == 0) endEpoch = Long.MAX_VALUE;\n            else endEpoch = endEpoch - 1 + startEpoch;\n            Timestamp staleUntilAtLeast = deserializeNullable(in);\n            int count = in.readUnsignedVInt32();\n\n            TxnId[] bounds = new TxnId[count];","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/service/accord/serializers/CommandStoreSerializers.java#L260-L296","documentation":"CommandStoreSerializers.cast packs a RedundantStatus value into 16 bits for the wire format. If the long value exceeds 0xFFFF (65535) it cannot fit in a short, so serialize throws IllegalStateException: supporting larger values would require a wire-format change. This is a hard limit of the current Accord RedundantBefore serialization scheme.","triggerScenarios":"serialize calls cast with a RedundantStatus/Bounds value > 65535, e.g. an epoch or position counter that grew beyond 16 bits before being written for RedundantBefore.","commonSituations":"Very long-running clusters where Accord epochs or command IDs grow large; tests that synthetically inflate epoch counters; a future format change raising the limit but writing to nodes on the old format.","solutions":["Check the value being cast (epoch/position) to confirm it really exceeds 0xFFFF; if it is unexpected, investigate counter growth/reset logic.","For legitimately large values, extend the wire format to 4+ bytes for RedundantStatus, coordinating the change across the cluster.","As a short-term mitigation, restart/reset epoch counters so values stay below 65535 until the serialization change ships."],"exampleFix":"// before\nif ((v & ~0xFFFF) != 0)\n    throw new IllegalStateException(\"Cannot serialize RedundantStatus larger than 0xFFFF. Requires serialization changes.\");\nreturn (short)v;\n// after (wire-format change)\nin.putInt(v); out.writeInt(cast32(v));\nprivate int cast32(long v) { if ((v & ~0xFFFFFFFFL) != 0) throw ...; return (int)v; }","handlingStrategy":"validation","validationCode":"long v = status.get();\nif ((v & ~0xFFFFL) != 0)\n    throw new IllegalArgumentException(\"RedundantStatus value \" + v + \" exceeds 0xFFFF serialization limit\");\nserializer.serialize(status, out, version);","typeGuard":null,"tryCatchPattern":"try {\n    serializer.serialize(status, out, version);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"larger than 0xFFFF\"))\n        logger.error(\"RedundantStatus overflow; epoch/counter growth exceeded wire format\", e);\n    else throw e;\n}","preventionTips":["Monitor Accord epoch/position counter growth; alert before values approach 65535.","Plan wire-format upgrades (wider fields) before long-lived clusters hit the limit.","Add assertions/tests that serialize boundary values 0xFFFF and 0x10000."],"tags":["serialization","accord","overflow","wire-format"],"backgroundTag":"value-out-of-range","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"}