{"record":{"id":"df2ec2e262befd07","repo":"clockworklabs/SpacetimeDB","slug":"unknown-compression-type","errorCode":null,"errorMessage":"Unknown compression type","messagePattern":"Unknown compression type","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sdks/csharp/src/CompressionHelpers.cs","lineNumber":64,"sourceCode":"        /// Ensures efficient decompression by reading the entire stream at once to avoid\n        /// performance issues with certain stream implementations.\n        /// Throws <see cref=\"InvalidOperationException\"/> if an unknown compression type is encountered.\n        /// </summary>\n        /// <param name=\"bytes\">The compressed and encoded server message as a byte array.</param>\n        /// <returns>The deserialized <see cref=\"ServerMessage\"/> object.</returns>\n        internal static ServerMessage DecompressDecodeMessage(byte[] bytes)\n        {\n            using var stream = new MemoryStream(bytes);\n\n            // The stream will never be empty. It will at least contain the compression algo.\n            var compression = (CompressionAlgos)stream.ReadByte();\n            // Conditionally decompress and decode.\n            Stream decompressedStream = compression switch\n            {\n                CompressionAlgos.None => stream,\n                CompressionAlgos.Brotli => BrotliReader(stream),\n                CompressionAlgos.Gzip => GzipReader(stream),\n                _ => throw new InvalidOperationException(\"Unknown compression type\"),\n            };\n\n            // TODO: consider pooling these.\n            // DO NOT TRY TO TAKE THIS OUT. The BrotliStream ReadByte() implementation allocates an array\n            // PER BYTE READ. You have to do it all at once to avoid that problem.\n            MemoryStream memoryStream = new MemoryStream();\n            decompressedStream.CopyTo(memoryStream);\n            memoryStream.Seek(0, SeekOrigin.Begin);\n            return new ServerMessage.BSATN().Read(new BinaryReader(memoryStream));\n        }\n\n        /// <summary>\n        /// Prepare to read a BsatnRowList.\n        ///\n        /// This could return an IEnumerable, but we return the reader and row count directly to avoid an allocation.\n        /// It is legitimate to repeatedly call <c>IStructuralReadWrite.Read<T></c> <c>rowCount</c> times on the resulting\n        /// BinaryReader:\n        /// Our decoding infrastructure guarantees that reading a value consumes the correct number of bytes","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/sdks/csharp/src/CompressionHelpers.cs#L46-L82","documentation":"Every ServerMessage arriving over the websocket starts with one byte naming the compression algorithm (0=None, 1=Brotli, 2=Gzip). CompressionHelpers.DecompressDecodeMessage casts that byte to the CompressionAlgos enum and throws InvalidOperationException for any other value. The client's parse loop catches it, logs the exception, fails pending operations and disconnects — so the observable effect is a dropped connection.","triggerScenarios":"A server newer than the SDK using an algorithm this SDK version does not know (e.g. a newly introduced algo id >= 3); a corrupted/truncated websocket frame; or test code injecting arbitrary bytes through OnMessageReceived/IsTesting paths.","commonSituations":"Client SDK package older than a freshly upgraded SpacetimeDB server (version skew); pinned old SDK against maincloud; byte-level test fixtures that forgot the leading algo byte.","solutions":["Upgrade the C# SDK package to the release matching your server version","As a workaround, reconnect with WithCompression(Compression.None) so a conformant server sends uncompressed messages (algo byte 0)","If you feed raw bytes in tests, ensure the first byte is 0, 1 or 2 before injecting the message","If SDK and server versions already match, capture the frame and report it as a SpacetimeDB bug"],"exampleFix":"// before\nconn.OnMessageReceived(arbitraryBytes, DateTime.UtcNow); // fixture without algo byte\n\n// after\nvar fixedBytes = new byte[] { (byte)CompressionAlgos.None }.Concat(arbitraryBytes).ToArray();\nconn.OnMessageReceived(fixedBytes, DateTime.UtcNow);","handlingStrategy":"validation","validationCode":"// When injecting raw frames (tests), verify the algo byte first:\nbool FrameHasKnownCompression(byte[] frame) =>\n    frame.Length > 0 && frame[0] is 0 or 1 or 2; // None, Brotli, Gzip","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pin the C# SDK and SpacetimeDB server to the same release line","Register OnDisconnect to surface decompression failures instead of silent drops","Keep websocket frame fixtures prefixed with the compression byte"],"tags":["compression","websocket","version-skew","csharp"],"backgroundTag":"unsupported-compression-algorithm","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}