{"record":{"id":"8de38edff822b3c8","repo":"SixLabors/ImageSharp","slug":"the-ani-animation-header-declares-an-invalid-size","errorCode":null,"errorMessage":"The ANI animation header declares an invalid size.","messagePattern":"The ANI animation header declares an invalid size\\.","errorType":"exception","errorClass":"InvalidImageContentException","httpStatus":null,"severity":"error","filePath":"src/ImageSharp/Formats/Ani/AniDecoderCore.cs","lineNumber":315,"sourceCode":"    /// <summary>\n    /// Parses the mandatory 36-byte ANI header and copies its observable values to image metadata.\n    /// </summary>\n    /// <param name=\"stream\">The ANI stream.</param>\n    /// <param name=\"chunkSize\">The ANI header chunk size.</param>\n    private void ReadAniHeader(BufferedReadStream stream, uint chunkSize)\n    {\n        if (chunkSize < AniHeader.Size)\n        {\n            throw new InvalidImageContentException(\"The ANI animation header is truncated.\");\n        }\n\n        Span<byte> data = this.buffer;\n        ReadExactly(stream, data, \"ANI header\");\n        this.header = AniHeader.Parse(data);\n\n        if (this.header.BytesInHeader < AniHeader.Size || this.header.BytesInHeader > chunkSize)\n        {\n            throw new InvalidImageContentException(\"The ANI animation header declares an invalid size.\");\n        }\n\n        this.aniMetadata.Width = this.header.Width;\n        this.aniMetadata.Height = this.header.Height;\n        this.aniMetadata.BitCount = this.header.BitCount;\n        this.aniMetadata.Planes = this.header.Planes;\n        this.aniMetadata.DisplayRate = this.header.DisplayRate;\n        this.aniMetadata.Flags = this.header.Flags;\n    }\n\n    /// <summary>\n    /// Reads a RIFF list type and records or parses its contents.\n    /// </summary>\n    /// <param name=\"stream\">The ANI stream.</param>\n    /// <param name=\"listEnd\">The exclusive end of the list payload.</param>\n    private void ReadList(BufferedReadStream stream, long listEnd)\n    {\n        if (listEnd - stream.Position < sizeof(uint))","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/SixLabors/ImageSharp/blob/59ce6af6fc29027cda277ef62d4d1694a8acce91/src/ImageSharp/Formats/Ani/AniDecoderCore.cs#L297-L333","documentation":"The ANI header contains a self-describing 'cbSize' (BytesInHeader) field, typically 36. The decoder validates that this declared size is at least the structural header size and no larger than the enclosing chunk's size; any other value makes the header internally inconsistent, so InvalidImageContentException is thrown. This guards against headers whose in-file size field contradicts the actual chunk.","triggerScenarios":"Calling Decode/Identify where the parsed header's BytesInHeader is 0 or below 36, or exceeds the 'anih' chunk size — usually from writers that fill the field incorrectly or files whose header bytes were corrupted.","commonSituations":"Hand-written ANI generators that leave cbSize zeroed; files patched by tools that resized the 'anih' chunk without updating the internal cbSize; bit-rot flipping the size field.","solutions":["Ensure the header's cbSize field equals the 'anih' chunk size (normally 36) — patch or regenerate the header.","Re-export the ANI with a conformant tool so cbSize and chunk size agree.","If you write ANI files yourself, set the JIF/cbSize field to sizeof(ANIHEADER) = 36 when serializing."],"exampleFix":"// before: cbSize=0 in the anih payload\n// after: Marshal.SizeOf<AniHeader>() == 36 written into the header at offset 0\nheader.BytesInHeader = 36;","handlingStrategy":"validation","validationCode":"// The first 4 bytes of anih payload are cbSize; require it to be 36\nstatic bool AnihCbSizeValid(string path)\n{\n    using var fs = File.OpenRead(path);\n    Span<byte> buf = stackalloc byte[8];\n    fs.Seek(12, SeekOrigin.Begin);\n    while (fs.Read(buf) == 8)\n    {\n        uint sz = BinaryPrimitives.ReadUInt32LittleEndian(buf.Slice(4, 4));\n        if (buf.Slice(0, 4).SequenceEqual(\"anih\"u8))\n        {\n            Span<byte> pay = stackalloc byte[4];\n            return fs.Read(pay) == 4 && BinaryPrimitives.ReadUInt32LittleEndian(pay) == 36;\n        }\n        fs.Seek((long)((sz + 1) & ~1u), SeekOrigin.Current);\n    }\n    return false;\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    using Image<Rgba32> img = Image.Load<Rgba32>(aniStream);\n}\ncatch (InvalidImageContentException ex)\n{\n    logger.LogError(ex, \"ANI header cbSize is inconsistent with the anih chunk.\");\n}","preventionTips":["When serializing ANI headers, set cbSize to 36 (the fixed header size) explicitly.","After resizing an 'anih' chunk with editing tools, rewrite the internal cbSize to match.","Checksum cursor assets so header field corruption is detected before load."],"tags":["ani","header-validation","riff","image-decoding"],"backgroundTag":"invalid-image-content","analyzedSha":"59ce6af6fc29027cda277ef62d4d1694a8acce91","analyzedAt":"2026-09-13T18:34:59.331Z","contentChangedAt":"2026-09-13T18:34:59.331Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}