SixLabors/ImageSharp · error · NotSupportedException

Bit depth is not supported or not valid.

Error message

Bit depth is not supported or not valid.

What it means

PngEncoderCore's bit-depth selection helper throws this NotSupportedException when the chosen (colorType, bitDepth) pair is not in PngConstants.ColorTypes — i.e. the depth is not legal for that PNG color type (for example 16-bit palette, or 1/2/4-bit RGB). It is the encoder-side mirror of the IHDR validation the decoder performs.

Solutions

  1. Use a valid color type/bit depth combination (palette: 1/2/4/8; grayscale: 1/2/4/8/16; gray-alpha, RGB, RGBA: 8 or 16).
  2. Omit BitDepth (leave default) and let the encoder derive a valid depth from the pixel type.
  3. If palette output is needed at 8-bit, set BitDepth = Bit8, or switch ColorType to Rgb/RgbWithAlpha for 16-bit.
  4. Log and validate the encoder options against PngConstants.ColorTypes before calling Save.

Example fix

// before
var encoder = new PngEncoder { ColorType = PngColorType.Palette, BitDepth = PngBitDepth.Bit16 };
image.SaveAsPng("out.png", encoder); // throws
// after
var encoder = new PngEncoder { ColorType = PngColorType.Palette, BitDepth = PngBitDepth.Bit8 };
image.SaveAsPng("out.png", encoder);
Defensive patterns

Strategy: validation

Validate before calling

// validate encoder options against the spec table before saving
static bool IsValidPngDepth(PngColorType t, PngBitDepth d) => t switch
{
    PngColorType.Palette => d is PngBitDepth.Bit1 or PngBitDepth.Bit2 or PngBitDepth.Bit4 or PngBitDepth.Bit8,
    PngColorType.Grayscale => true,
    _ => d is PngBitDepth.Bit8 or PngBitDepth.Bit16
};

Type guard

static bool IsValidPngDepth(PngColorType t, PngBitDepth d) =>
    t == PngColorType.Palette
        ? d is PngBitDepth.Bit1 or PngBitDepth.Bit2 or PngBitDepth.Bit4 or PngBitDepth.Bit8
        : d is PngBitDepth.Bit8 or PngBitDepth.Bit16;

Try / catch

try
{
    image.SaveAsPng(path, encoder);
}
catch (NotSupportedException ex) when (ex.Message.Contains("Bit depth"))
{
    image.SaveAsPng(path, new PngEncoder()); // defaults derive a valid depth
}

Prevention

When it happens

Trigger: Saving to PNG with PngEncoder BitDepth/ColorType options that combine illegally, e.g. `new PngEncoder { ColorType = PngColorType.Palette, BitDepth = PngBitDepth.Bit16 }`, or quantized 1/2/4-bit output requested for an unsupported color type.

Common situations: Hand-built PngEncoder option sets, porting settings from another library's API, or blindly reusing previously captured encoder options across differently processed images.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/ImageSharp/Formats/Png/PngEncoderCore.cs:1797

            byte quantizedBits = (byte)Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(quantizedFrame!.Palette.Length), 1, 8);
            byte bits = Math.Max(bitDepth, quantizedBits);

            // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk
            // We check again for the bit depth as the bit depth of the color palette from a given quantizer might not
            // be within the acceptable range.
            bits = bits switch
            {
                3 => 4,
                >= 5 and <= 7 => 8,
                _ => bits
            };

            bitDepth = bits;
        }

        if (Array.IndexOf(PngConstants.ColorTypes[colorType], bitDepth) < 0)
        {
            throw new NotSupportedException("Bit depth is not supported or not valid.");
        }

        return bitDepth;
    }

    /// <summary>
    /// Calculates the correct number of bytes per pixel for the given color type.
    /// </summary>
    /// <param name="pngColorType">The color type.</param>
    /// <param name="use16Bit">Whether to use 16 bits per component.</param>
    /// <returns>Bytes per pixel.</returns>
    private static int CalculateBytesPerPixel(PngColorType? pngColorType, bool use16Bit)
        => pngColorType switch
        {
            PngColorType.Grayscale => use16Bit ? 2 : 1,
            PngColorType.GrayscaleWithAlpha => use16Bit ? 4 : 2,
            PngColorType.Palette => 1,
            PngColorType.Rgb => use16Bit ? 6 : 3,

View on GitHub (pinned to 59ce6af6fc)