SixLabors/ImageSharp · error · InvalidOperationException

Cannot remove last frame.

Error message

Cannot remove last frame.

What it means

RemoveFrame refuses to remove the only remaining frame because every Image must retain at least one frame. Attempting to remove frame 0 when Count == 1 would leave the image in an invalid, frame-less state, so InvalidOperationException is thrown.

Solutions

  1. Check Count == 1 (or index == 0 && Count == 1) before removing and stop the loop at the last frame.
  2. Iterate down to Count - 1 frames only: for (int i = image.Frames.Count - 1; i > 0; i--) RemoveFrame(i).
  3. If a truly empty result is required, construct a new image instead of stripping the last frame.

Example fix

// before
for (int i = image.Frames.Count - 1; i >= 0; i--)
{
    image.Frames.RemoveFrame(i);
}
// after
for (int i = image.Frames.Count - 1; i > 0; i--)
{
    image.Frames.RemoveFrame(i);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (image.Frames.Count <= 1 && index == 0) return; // refuse to strip the last frame

Type guard

static bool CanRemoveFrame(Image<TPixel> image, int index) => image.Frames.Count > 1 && index >= 0 && index < image.Frames.Count;

Try / catch

try { image.Frames.RemoveFrame(index); }
catch (InvalidOperationException ex) when (image.Frames.Count == 1) { /* keep the last frame */ }

Prevention

When it happens

Trigger: Calling image.Frames.RemoveFrame(0) on an image that contains exactly one frame, or looping RemoveFrame over all indexes including the last remaining one.

Common situations: Animation-trimming code that removes frames without stopping before the last one, or generic 'remove processed frames' logic that doesn't special-case the final frame.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/ImageSharp/ImageFrameCollection{TPixel}.cs:208

    public ImageFrame<TPixel> AddFrame(TPixel[] source)
    {
        Guard.NotNull(source, nameof(source));

        return this.AddFrame(source.AsSpan());
    }

    /// <summary>
    /// Removes the frame at the specified index and frees all freeable resources associated with it.
    /// </summary>
    /// <param name="index">The zero-based index of the frame to remove.</param>
    /// <exception cref="InvalidOperationException">Cannot remove last frame.</exception>
    public override void RemoveFrame(int index)
    {
        this.EnsureNotDisposed();

        if (index == 0 && this.Count == 1)
        {
            throw new InvalidOperationException("Cannot remove last frame.");
        }

        ImageFrame<TPixel> frame = this.frames[index];
        this.frames.RemoveAt(index);
        frame.Dispose();
    }

    /// <inheritdoc />
    public override bool Contains(ImageFrame frame)
    {
        this.EnsureNotDisposed();

        return frame is ImageFrame<TPixel> specific && this.frames.Contains(specific);
    }

    /// <summary>
    /// Determines whether the <seealso cref="ImageFrameCollection{TPixel}"/> contains the <paramref name="frame"/>.
    /// </summary>

View on GitHub (pinned to 59ce6af6fc)