stride3d/stride · error · InvalidOperationException

Cannot end one SpriteBatch while another is using…

Error message

Cannot end one SpriteBatch while another is using SpriteSortMode.Immediate

What it means

In SpriteSortMode.Immediate the batch draws sprites directly as they are submitted. If one SpriteBatch is in Immediate mode, ending a second SpriteBatch (with queued draws) would change device state and break the in-flight immediate rendering, so End throws this InvalidOperationException.

Solutions

  1. Call End() on the Immediate-mode SpriteBatch before ending any other batch with pending draws.
  2. Restructure rendering so Immediate and deferred batches are not interleaved.
  3. Switch the immediate batch to a deferred sort mode (e.g. BackToFront) if immediate semantics are not required.
  4. Ensure End is called on the immediate batch even on early-exit paths (try/finally).

Example fix

// before
immediateBatch.Begin(SpriteSortMode.Immediate, blend);
deferredBatch.Begin(SpriteSortMode.Deferred, blend);
deferredBatch.End(); // throws
// after
immediateBatch.Begin(SpriteSortMode.Immediate, blend);
immediateBatch.End();
deferredBatch.Begin(SpriteSortMode.Deferred, blend);
deferredBatch.End();
Defensive patterns

Strategy: validation

Validate before calling

// before ending a deferred batch, ensure no immediate batch is active
bool immediateActive = false; // track when Begin(SpriteSortMode.Immediate, ...) is called
if (!immediateActive) deferredBatch.End();

Type guard

bool CanEndBatch(BatchBase b) => !immediateBatchActive || ReferenceEquals(b, immediateBatch);

Try / catch

try { deferredBatch.End(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("SpriteSortMode.Immediate"))
{
    immediateBatch.End();
    deferredBatch.End();
}

Prevention

When it happens

Trigger: spriteBatchA.Begin(Immediate, ...) is active and batchSizeB.End() is called while spriteBatchB still has queued draws (drawsQueueCount > 0); interleaving an immediate-mode batch with a deferred batch's End without ending the immediate batch first.

Common situations: Mixing an immediate-mode SpriteBatch for per-pixel custom effects with a normal deferred SpriteBatch for text/UI in the same frame; forgetting End on the immediate batch before flushing the other one.

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 stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/7c2848692543da60. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Graphics/BatchBase.cs:299

        }

        /// <summary>
        /// Flushes the sprite batch and restores the device state to how it was before Begin was called.
        /// </summary>
        public void End()
        {
            CheckBeginHasBeenCalled("End");

            if (sortMode == SpriteSortMode.Immediate)
            {
                ResourceContext.IsInImmediateMode = false;
            }
            else if (drawsQueueCount > 0)
            {
                // Draw the queued sprites now.
                if (ResourceContext.IsInImmediateMode)
                {
                    throw new InvalidOperationException("Cannot end one SpriteBatch while another is using SpriteSortMode.Immediate");
                }

                // If not immediate, then setup and render all sprites
                PrepareForRendering();
                FlushBatch();
            }

            ResourceContext = null;

            // We are with begin pair
            isBeginCalled = false;
        }

        private void SortSprites()
        {
            IComparer<int> comparer;

            switch (sortMode)

View on GitHub (pinned to 96fad776d2)