SixLabors/ImageSharp · error · InvalidImageContentException

Unexpected end of stream while reading gif XMP data

Error message

Unexpected end of stream while reading gif XMP data

What it means

Thrown when a GIF XMP application extension block is truncated: ReadXmpData reaches the end of the stream before finding the XMP magic trailer that terminates the payload. SixLabors.ImageSharp throws InvalidImageContentException because the image data itself is malformed/incomplete.

Solutions

  1. Verify the GIF file is complete and re-download or re-export it from the original source
  2. Wrap Image.Load in a try-catch for InvalidImageContentException and treat the file as corrupt
  3. Check the GIF with a validator or hex inspector: the XMP block must end with the 257-byte magic trailer (0xFE followed by 256 bytes including the terminating 0x00)
  4. If files come from a producer of GIFs, fix that encoder to emit the complete XMP block including the magic trailer

Example fix

// before
var image = Image.Load("animated.gif");
// after
try
{
    var image = Image.Load("animated.gif");
}
catch (InvalidImageContentException)
{
    // corrupt/truncated GIF (e.g. missing XMP magic trailer)
    image = null;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// GIF must contain a full XMP block ending in the magic trailer
static bool GifLooksTruncated(string path) =>
    new FileInfo(path).Length == 0; // real content validation happens on load

Type guard

static bool IsValidImageContentException(Exception ex) => ex is InvalidImageContentException;

Try / catch

try
{
    var image = Image.Load(path);
}
catch (InvalidImageContentException ex)
{
    // GIF XMP data truncated: file is corrupt, do not retry
    HandleCorruptImage(path, ex);
}

Prevention

When it happens

Trigger: Calling Image.Load/LoadAsync (or GifDecoder) on a GIF whose XMP application extension data chunk is cut off mid-extension, e.g. a partially downloaded or truncated file where the 0x00 magic trailer never appears.

Common situations: Interrupted downloads or uploads of GIFs; file corruption on disk; a tool or hand-rolled encoder writing an incomplete XMP sub-block; CDN/proxy truncation of large GIF payloads.

Related errors


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

Appendix: source

Thrown at src/ImageSharp/Formats/Gif/Sections/GifXmpApplicationExtension.cs:36

    public int ContentLength => (this.Data.Length > 0) ? this.Data.Length + 269 : 0;

    /// <summary>
    /// Gets the raw Data.
    /// </summary>
    public byte[] Data { get; }

    /// <summary>
    /// Reads the XMP metadata from the specified stream.
    /// </summary>
    /// <param name="stream">The stream to read from.</param>
    /// <param name="allocator">The memory allocator.</param>
    /// <returns>The XMP metadata</returns>
    public static GifXmpApplicationExtension Read(BufferedReadStream stream, MemoryAllocator allocator)
    {
        byte[] xmpBytes = ReadXmpData(stream, allocator, out bool terminated);
        if (!terminated)
        {
            throw new InvalidImageContentException("Unexpected end of stream while reading gif XMP data");
        }

        // Exclude the "magic trailer", see XMP Specification Part 3, 1.1.2 GIF
        int xmpLength = xmpBytes.Length - 256; // 257 - unread 0x0
        byte[] buffer = [];
        if (xmpLength > 0)
        {
            buffer = new byte[xmpLength];
            xmpBytes.AsSpan(0, xmpLength).CopyTo(buffer);
            stream.Skip(1); // Skip the terminator.
        }

        return new GifXmpApplicationExtension(buffer);
    }

    public int WriteTo(Span<byte> buffer)
    {
        int bytesWritten = 0;

View on GitHub (pinned to 59ce6af6fc)