SixLabors/ImageSharp · error · InvalidImageContentException

Unexpected end of stream while reading gif application…

Error message

Unexpected end of stream while reading gif application extension

What it means

Thrown when the GIF stream ends in the middle of the Netscape application extension's data sub-block. The decoder expects the full NetscapeLoopingSubBlockSize bytes followed by a block terminator; fewer bytes means truncated or corrupt input. Raised as InvalidImageContentException.

Solutions

  1. Re-download or re-export the GIF so the file is complete
  2. Verify file size against the server-provided content length before decoding
  3. Strip the broken Netscape extension with a GIF tool (e.g. gifsicle -b) to salvage the animation
  4. Wrap decode in try-catch and fall back to a placeholder image

Example fix

// before
var image = Image.Load(stream);
// after
try { var image = Image.Load(stream); }
catch (InvalidImageContentException ex) { logger.LogWarning(ex, "Truncated GIF"); image = CreatePlaceholder(); }
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the stream is large enough to contain a Netscape extension
if (stream.CanSeek && stream.Length < 14) throw new InvalidDataException("Truncated GIF");

Try / catch

try { return Image.Load(stream); }
catch (InvalidImageContentException ex) when (ex.Message.Contains("gif application extension")) { return RepairOrPlaceholder(stream); }

Prevention

When it happens

Trigger: Image.Load/Decode on a GIF where the Netscape looping extension (0x21 0xFF 0x0B) sub-block read returns fewer than the expected bytes — i.e. the stream ends inside the extension.

Common situations: Interrupted downloads, files cut off mid-transfer, GIFs generated by buggy encoders that omit the extension terminator.

Related errors


AI-assisted analysis of SixLabors/ImageSharp@59ce6af6fc (2026-09-13). Data as JSON: /api/errors/8e07ee528ce1c76c. Report an issue: GitHub.

Appendix: source

Thrown at src/ImageSharp/Formats/Gif/GifDecoderCore.cs:452

    }

    /// <summary>
    /// Reads the GIF NETSCAPE looping application extension.
    /// </summary>
    /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
    private void ReadNetscapeApplicationExtension(BufferedReadStream stream) =>
        this.ExecuteAncillarySegmentAction(() => this.ReadNetscapeApplicationExtensionData(stream));

    /// <summary>
    /// Reads the GIF NETSCAPE looping application extension data.
    /// </summary>
    /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
    private void ReadNetscapeApplicationExtensionData(BufferedReadStream stream)
    {
        int bytesRead = stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize);
        if (bytesRead != GifConstants.NetscapeLoopingSubBlockSize)
        {
            throw new InvalidImageContentException("Unexpected end of stream while reading gif application extension");
        }

        this.gifMetadata!.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer[1..]).RepeatCount;

        int terminator = stream.ReadByte();
        if (terminator == -1)
        {
            throw new InvalidImageContentException("Unexpected end of stream while reading gif application extension");
        }
    }

    /// <summary>
    /// Skips over a block or reads its terminator.
    /// </summary>
    /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
    /// <param name="blockSize">The length of the block to skip.</param>
    private static void SkipBlock(BufferedReadStream stream, int blockSize = 0)
    {

View on GitHub (pinned to 59ce6af6fc)