{"record":{"id":"9bd0aab3b715123b","repo":"SixLabors/ImageSharp","slug":"the-ani-animation-header-is-truncated","errorCode":null,"errorMessage":"The ANI animation header is truncated.","messagePattern":"The ANI animation header is truncated\\.","errorType":"exception","errorClass":"InvalidImageContentException","httpStatus":null,"severity":"error","filePath":"src/ImageSharp/Formats/Ani/AniDecoderCore.cs","lineNumber":306,"sourceCode":"            stream.Position = GetPaddedEnd(dataEnd, chunk.Size, containerEnd);\n        }\n\n        if (!headerFound)\n        {\n            throw new InvalidImageContentException(\"The ANI file does not contain an animation header.\");\n        }\n    }\n\n    /// <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    }","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/SixLabors/ImageSharp/blob/59ce6af6fc29027cda277ef62d4d1694a8acce91/src/ImageSharp/Formats/Ani/AniDecoderCore.cs#L288-L324","documentation":"The 'anih' chunk must be at least AniHeader.Size (36) bytes to hold the full ANI header structure. When the chunk declares a smaller size, the header cannot be parsed completely and InvalidImageContentException is thrown. This catches headers written by non-conformant producers or truncated files.","triggerScenarios":"Calling Decode/Identify where the 'anih' chunk's size field is < 36 — e.g. a 12- or 16-byte header from a buggy writer, or a chunk whose declared size exceeds remaining stream bytes so only part is readable.","commonSituations":"Truncated downloads where the 'anih' chunk size was written correctly but the payload was cut off; minimal header variants from old or hand-rolled ANI writers.","solutions":["Check the 'anih' chunk size field: it must be >= 36; extend the header to 36 bytes (padding the tail) if you control the writer.","Re-download the file if the chunk payload was truncated in transit.","Re-export the animation with a mainstream tool that always emits the full 36-byte header."],"exampleFix":"// before: [anih size=16][16 bytes]\n// after: [anih size=36][36 bytes incl. reserved fields]","handlingStrategy":"validation","validationCode":"// Read the anih chunk size field and require >= 36 before decoding\nstatic bool AnihChunkIsFullSize(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)) return sz >= 36 && fs.Length - fs.Position >= sz;\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 chunk truncated.\");\n}","preventionTips":["Verify downloads are complete before parsing (truncation is the most common cause).","Ensure ANI writers always emit the full 36-byte header, padding if needed.","Check chunk size against remaining file length during ingestion."],"tags":["ani","truncated-header","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"}