SixLabors/ImageSharp · error · InvalidImageContentException
The stream does not contain an ANI RIFF container.
Error message
The stream does not contain an ANI RIFF container.
What it means
The ANI decoder first reads the 12-byte RIFF header and verifies the 'RIFF' FourCC and the 'ACON' (ANI form) type. If either does not match, the stream is not an ANI container and InvalidImageContentException is thrown. This is the earliest structural validation, so it usually means the stream is not ANI at all or is corrupt from byte zero.
Solutions
- Confirm the file really is an ANI (first 12 bytes: 'RIFF' + size + 'ACON'); check with a hex editor or `file` command.
- Re-download the file — an HTML error page or truncated transfer often replaces the real bytes.
- Use Image.DetectFormatAsync before decode so a non-ANI stream is routed to the right decoder or rejected clearly.
Example fix
// before
using Image<Rgba32> img = Image.Load<Rgba32>(path); // assumes ANI
// after
IImageFormat fmt = await Image.DetectFormatAsync(path);
if (fmt?.Name != "ANI") throw new NotSupportedException($"{fmt?.Name ?? "unknown"} is not ANI"); Defensive patterns
Strategy: validation
Validate before calling
bool IsAniContainer(Stream s)
{
byte[] h = new byte[12];
if (s.Read(h, 0, 12) != 12) return false;
s.Position = 0;
return h.AsSpan(0, 4).SequenceEqual("RIFF"u8) && h.AsSpan(8, 4).SequenceEqual("ACON"u8);
} Prevention
- Always call Image.DetectFormatAsync before loading with an assumed format.
- Check HTTP responses: ensure you saved the binary payload, not an HTML error page.
- Remember .ani is RIFF/ACON — a .wav or .webp will fail this exact check.
When it happens
Trigger: Calling Image.DecodeAsync/IdentifyAsync on a stream whose first 4 bytes are not 'RIFF' or whose bytes 8-12 are not the ANI form type (ACON): e.g. a plain .ico, .wav, .webp RIFF file, or a text/HTML error page saved with an .ani extension.
Common situations: Wrong-file-downloaded scenarios (server returns HTML with 200); confusing RIFF-family files (.wav/.webp) pointed at the ANI decoder; decoder auto-detection overridden or misconfigured.
Related errors
- The ANI RIFF container size is invalid.
- The ANI file does not contain an animation header.
- The ANI animation header is truncated.
- The ANI animation header declares an invalid size.
- The ANI file contains a truncated RIFF list.
AI-assisted analysis of SixLabors/ImageSharp@59ce6af6fc (2026-09-13).
Data as JSON: /api/errors/7307ee719151a0b9.
Report an issue: GitHub.
Appendix: source
Thrown at src/ImageSharp/Formats/Ani/AniDecoderCore.cs:250
/// </summary>
/// <param name="stream">The ANI stream.</param>
private void ParseContainer(BufferedReadStream stream)
{
// Parser-owned chunk state is replaced by the container currently being scanned.
this.frameLists.Clear();
this.sequence?.Dispose();
this.rates?.Dispose();
this.sequence = null;
this.rates = null;
long containerStart = stream.Position;
Span<byte> riffHeader = this.buffer[..AniConstants.RiffHeaderSize];
ReadExactly(stream, riffHeader, "RIFF header");
if (!riffHeader[..4].SequenceEqual(AniConstants.RiffFourCc)
|| !riffHeader.Slice(8, 4).SequenceEqual(AniConstants.AniFormTypeFourCc))
{
throw new InvalidImageContentException("The stream does not contain an ANI RIFF container.");
}
uint declaredSize = BinaryPrimitives.ReadUInt32LittleEndian(riffHeader[4..]);
if (declaredSize < sizeof(uint))
{
throw new InvalidImageContentException("The ANI RIFF container size is invalid.");
}
// RIFF size excludes the initial identifier and size field. Some real-world ANI files incorrectly
// include those eight bytes, so the physical stream length remains the hard read boundary.
long declaredEnd = checked(containerStart + 8 + declaredSize);
long containerEnd = Math.Min(declaredEnd, stream.Length);
bool headerFound = false;
while (stream.Position + AniConstants.ChunkHeaderSize <= containerEnd)
{
AniRiffChunkHeader chunk = this.ReadChunkHeader(stream);
long dataEnd = GetChunkDataEnd(stream, chunk.Size, containerEnd);View on GitHub (pinned to 59ce6af6fc)