SixLabors/ImageSharp · error · ImageFormatException

TGA image does not have a valid format.

Error message

TGA image does not have a valid format.

What it means

TgaDecoderCore.Decode wraps its whole decode in a catch for IndexOutOfRangeException and rethrows it as ImageFormatException with 'TGA image does not have a valid format.' This converts out-of-bounds reads caused by inconsistent TGA header/field data (offsets, color-map sizes, pixel counts that run past the buffer) into a clean format error with the original exception as InnerException. It signals the byte stream does not match any TGA layout the decoder can navigate safely.

Solutions

  1. Open the InnerException/stack to see which read went out of bounds, then inspect the TGA header (18 bytes) with a hex editor for implausible dimensions or color-map values.
  2. Re-export the image in a well-formed TGA (or convert to PNG) from the original source.
  3. Verify the file size matches what the producer wrote; re-transfer if truncated.
  4. Catch ImageFormatException and treat the input as invalid/unreadable rather than retrying.

Example fix

// before
using var image = Image.Load("legacy.tga");
// after
try
{
    using var image = Image.Load("legacy.tga");
}
catch (ImageFormatException ex)
{
    Console.WriteLine($"Invalid TGA: {ex.Message} (root: {ex.InnerException?.Message})");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Sanity-check the 18-byte TGA header before decode.
byte[] h = new byte[18];
using (var fs = File.OpenRead(path)) if (fs.Read(h, 0, 18) != 18) throw new InvalidDataException("Too short for TGA header.");
int width = h[12] | (h[13] << 8), height = h[14] | (h[15] << 8);
int depth = h[16];
if (width <= 0 || height <= 0 || depth is not (8 or 15 or 16 or 24 or 32))
    throw new InvalidDataException("Suspicious TGA header.");

Try / catch

try { using var img = Image.Load(path); }
catch (ImageFormatException ex)
{
    // InnerException holds the underlying IndexOutOfRangeException
    Log(ex.InnerException ?? ex, "TGA does not have a valid format.");
}

Prevention

When it happens

Trigger: Image.Load/Image.Identify on a TGA file whose declared header fields (width/height, color-map length/offset, pixel depth) cause row or color-map indexing to exceed the actual data — i.e. data shorter than the header promises.

Common situations: Truncated TGA files from interrupted uploads; TGA variants from old/obscure tools with nonstandard field layouts; renaming non-TGA files to .tga; fuzzed or corrupted images.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at src/ImageSharp/Formats/Tga/TgaDecoderCore.cs:200

                        this.ReadRle(stream, this.fileHeader.Width, this.fileHeader.Height, pixels, 4, origin);
                    }
                    else
                    {
                        this.ReadBgra32(stream, this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
                    }

                    break;

                default:
                    TgaThrowHelper.ThrowNotSupportedException("ImageSharp does not support this kind of tga files.");
                    break;
            }

            return image;
        }
        catch (IndexOutOfRangeException e)
        {
            throw new ImageFormatException("TGA image does not have a valid format.", e);
        }
    }

    /// <summary>
    /// Reads a uncompressed TGA image with a palette.
    /// </summary>
    /// <typeparam name="TPixel">The pixel type.</typeparam>
    /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
    /// <param name="width">The width of the image.</param>
    /// <param name="height">The height of the image.</param>
    /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
    /// <param name="palette">The color palette.</param>
    /// <param name="colorMapPixelSizeInBytes">Color map size of one entry in bytes.</param>
    /// <param name="origin">The image origin.</param>
    private void ReadPaletted<TPixel>(BufferedReadStream stream, int width, int height, Buffer2D<TPixel> pixels, Span<byte> palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
        where TPixel : unmanaged, IPixel<TPixel>
    {
        bool invertX = InvertX(origin);

View on GitHub (pinned to 59ce6af6fc)