SixLabors/ImageSharp · error · InvalidIccProfileException

Invalid CLUT size of

Error message

Invalid CLUT size of {size}

What it means

The CLUT (color lookup table) header inside a lut16/lutAtoB/lutBToA tag declares a data size value that is neither 1 (8-bit), 2 (16-bit), nor 4 (32-bit float). The reader only knows how to decode those three representations, so any other declared precision is treated as a corrupt or unsupported profile.

Solutions

  1. Regenerate the profile so the CLUT uses a standard 8-bit, 16-bit, or 32-bit float representation.
  2. Validate the profile with an ICC conformance tool before loading to pinpoint the malformed tag.
  3. Check the file for corruption (compare checksum, re-download or re-export).
  4. If support for a nonstandard size is genuinely needed, open an issue upstream - the library only handles sizes 1/2/4.
Defensive patterns

Strategy: try-catch

Try / catch

try { profile = IccReader.Read(stream); }
catch (InvalidIccProfileException ex) when (ex.Message.Contains("CLUT"))
{
    profile = IccProfile.Default;
}

Prevention

When it happens

Trigger: Reading an ICC profile whose lut16Type/lutAToBType/lutBToAType tag contains a CLUT with a declared entry-byte-size value other than 1, 2, or 4; corrupted bytes in the CLUT header can also produce an arbitrary value.

Common situations: Loading ICC profiles produced by buggy or non-conformant profiling software; profiles with flipped/shifted bits from bad transfers; attempting to read a profile variant the library does not support.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Lut.cs:60

    {
        // Grid-points are always 16 bytes long but only 0-inChCount are used.
        byte[] gridPointCount = new byte[inChannelCount];
        Buffer.BlockCopy(this.data, this.AddIndex(16), gridPointCount, 0, inChannelCount);

        if (!isFloat)
        {
            byte size = this.data[this.AddIndex(4)];   // First byte is info, last 3 bytes are reserved
            if (size == 1)
            {
                return this.ReadClut8(inChannelCount, outChannelCount, gridPointCount);
            }

            if (size == 2)
            {
                return this.ReadClut16(inChannelCount, outChannelCount, gridPointCount);
            }

            throw new InvalidIccProfileException($"Invalid CLUT size of {size}");
        }

        return this.ReadClutF32(inChannelCount, outChannelCount, gridPointCount);
    }

    /// <summary>
    /// Reads an 8 bit CLUT.
    /// </summary>
    /// <param name="inChannelCount">Input channel count.</param>
    /// <param name="outChannelCount">Output channel count.</param>
    /// <param name="gridPointCount">Grid point count for each CLUT channel.</param>
    /// <returns>The read CLUT8.</returns>
    public IccClut ReadClut8(int inChannelCount, int outChannelCount, byte[] gridPointCount)
    {
        int length = this.GetClutLength(inChannelCount, outChannelCount, gridPointCount, 1);

        const float Max = byte.MaxValue;

View on GitHub (pinned to 59ce6af6fc)