SixLabors/ImageSharp · error · InvalidImageContentException

Reached EOF while reading the header.

Error message

Reached EOF while reading the header.

What it means

Thrown by PbmDecoderCore.ProcessHeader when the stream ends before a complete PNM header (magic, width, height, and for non-mono formats the max pixel value) has been read. The decoder needs the entire header before allocating the pixel buffer; premature EOF means the file is truncated or not a PNM image. Implemented via the local ThrowPrematureEof helper in PbmDecoderCore.cs:186.

Solutions

  1. Verify the source file/stream is fully written and complete (compare file size against the producer's expected output).
  2. Re-download or re-export the image; the header bytes are unrecoverable.
  3. For streams, reset the stream position to 0 before passing it to Image.Identify/Image.Load.
  4. Check that the writer producing the file finished and disposed/flushed before the decoder reads it.

Example fix

// before
using var stream = File.OpenRead("partial.pgm");
using var image = Image.Load(stream);
// after
using var stream = File.OpenRead("partial.pgm");
if (stream.Length < 10) // smallest sane PNM header is longer than this
{
    throw new IOException("PNM file is truncated; re-obtain the file.");
}
stream.Position = 0;
using var image = Image.Load(stream);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the stream holds at least a minimal complete PNM header before decoding
if (!stream.CanSeek || stream.Length < 15)
    throw new InvalidDataException("Source too short to contain a PNM header");
stream.Position = 0;

Type guard

static bool HasMinimalPnmHeader(Stream s)
{
    if (!s.CanSeek || s.Length < 15) return false;
    Span<byte> buf = stackalloc byte[2];
    s.Read(buf);
    s.Position = 0;
    return buf[0] == (byte)'P' && buf[1] is >= (byte)'1' and <= (byte)'7';
}

Try / catch

try
{
    using var image = Image.Load(stream);
}
catch (InvalidImageContentException ex) when (ex.Message.Contains("EOF while reading the header"))
{
    throw new IOException("PNM source is truncated; re-obtain the file.", ex);
}

Prevention

When it happens

Trigger: Image.Identify or Image.Load on a PNM stream that ends mid-header — e.g. a 0-byte or partially-written file, a stream that was not rewound, or a network source cut off after only the magic bytes.

Common situations: Truncated uploads/downloads, reading from a stream positioned after data was consumed, writing PNM files without flushing/closing the writer, or trying to decode a PNM still being produced by another process.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs:186

            }

            stream.SkipWhitespaceAndComments();
        }
        else
        {
            this.componentType = PbmComponentType.Bit;
        }

        this.pixelSize = new Size(width, height);
        this.Dimensions = this.pixelSize;
        this.metadata = new ImageMetadata();
        PbmMetadata meta = this.metadata.GetPbmMetadata();
        meta.Encoding = this.encoding;
        meta.ColorType = this.colorType;
        meta.ComponentType = this.componentType;

        [DoesNotReturn]
        static void ThrowPrematureEof() => throw new InvalidImageContentException("Reached EOF while reading the header.");
    }

    private void ProcessPixels<TPixel>(BufferedReadStream stream, Buffer2D<TPixel> pixels)
        where TPixel : unmanaged, IPixel<TPixel>
    {
        if (this.encoding == PbmEncoding.Binary)
        {
            BinaryDecoder.Process(this.configuration, pixels, stream, this.colorType, this.componentType);
        }
        else
        {
            PlainDecoder.Process(this.configuration, pixels, stream, this.colorType, this.componentType);
        }
    }

    private void ProcessUpscaling<TPixel>(Image<TPixel> image)
        where TPixel : unmanaged, IPixel<TPixel>
    {

View on GitHub (pinned to 59ce6af6fc)