|
| 1 | +--- |
| 2 | +title: "Breaking change: DeflateStream and GZipStream write headers and footers for empty payload" |
| 3 | +description: "Learn about the breaking change in .NET 11 where DeflateStream and GZipStream always write headers and footers to the output, even for empty payloads." |
| 4 | +ms.date: 01/09/2026 |
| 5 | +ai-usage: ai-assisted |
| 6 | +--- |
| 7 | + |
| 8 | +# DeflateStream and GZipStream write headers and footers for empty payload |
| 9 | + |
| 10 | +<xref:System.IO.Compression.DeflateStream> and <xref:System.IO.Compression.GZipStream> now always write format headers and footers to the output stream, even when no data is written. This ensures the output is a valid compressed stream according to the Deflate and GZip specifications. |
| 11 | + |
| 12 | +## Version introduced |
| 13 | + |
| 14 | +.NET 11 Preview 1 |
| 15 | + |
| 16 | +## Previous behavior |
| 17 | + |
| 18 | +Previously, `DeflateStream` and `GZipStream` didn't produce any output if no data was written to the stream. This resulted in an empty output stream when compressing an empty input. |
| 19 | + |
| 20 | +```csharp |
| 21 | +using var output = new MemoryStream(); |
| 22 | +using (var deflate = new DeflateStream(output, CompressionMode.Compress)) |
| 23 | +{ |
| 24 | + // No data written. |
| 25 | +} |
| 26 | +Console.WriteLine(output.Length); // 0 |
| 27 | +``` |
| 28 | + |
| 29 | +## New behavior |
| 30 | + |
| 31 | +Starting in .NET 11, `DeflateStream` and `GZipStream` always write the appropriate headers and footers to the output stream, even when no data is written. This ensures the output contains valid compressed data according to the format specifications. |
| 32 | + |
| 33 | +```csharp |
| 34 | +using var output = new MemoryStream(); |
| 35 | +using (var deflate = new DeflateStream(output, CompressionMode.Compress)) |
| 36 | +{ |
| 37 | + // No data written. |
| 38 | +} |
| 39 | +Console.WriteLine(output.Length); // 2 (for Deflate) or 20 (for GZip). |
| 40 | +``` |
| 41 | + |
| 42 | +## Type of breaking change |
| 43 | + |
| 44 | +This change is a [behavioral change](../../categories.md#behavioral-change). |
| 45 | + |
| 46 | +## Reason for change |
| 47 | + |
| 48 | +Deflate and GZip compression formats include delimiters for the start and end of compressed data. The correct way to compress an empty payload with these formats includes only those delimiters. Some tools don't correctly react to empty content and always expect the compressed content to contain at least the appropriate header and footer. This change ensures compatibility with such tools and produces properly formatted compressed streams according to the specifications. |
| 49 | + |
| 50 | +## Recommended action |
| 51 | + |
| 52 | +If the previous behavior is desired, special-case empty content to not compress it via `DeflateStream` or `GZipStream`. |
| 53 | + |
| 54 | +```csharp |
| 55 | +byte[] dataToCompress = GetData(); |
| 56 | + |
| 57 | +if (dataToCompress.Length == 0) |
| 58 | +{ |
| 59 | + // Don't compress empty data. |
| 60 | + return Array.Empty<byte>(); |
| 61 | +} |
| 62 | + |
| 63 | +using var output = new MemoryStream(); |
| 64 | +using (var deflate = new DeflateStream(output, CompressionMode.Compress)) |
| 65 | +{ |
| 66 | + deflate.Write(dataToCompress); |
| 67 | +} |
| 68 | +return output.ToArray(); |
| 69 | +``` |
| 70 | + |
| 71 | +If you need to distinguish between empty and nonempty compressed streams, track whether any data was written or check the original uncompressed data length before compression. |
| 72 | + |
| 73 | +## Affected APIs |
| 74 | + |
| 75 | +- <xref:System.IO.Compression.DeflateStream?displayProperty=fullName> |
| 76 | +- <xref:System.IO.Compression.GZipStream?displayProperty=fullName> |
0 commit comments