stride3d/stride · error · InvalidOperationException
End must be called before functionName
Error message
End must be called before functionName
What it means
CheckEndHasBeenCalled throws when Begin() is invoked while isBeginCalled is still true, i.e. the previous Begin/End cycle was never completed with End(). BatchBase enforces one active Begin session per batch because Begin captures device state that End must restore.
Solutions
- Pair every Begin with exactly one End before calling Begin again.
- Audit render code for nested or duplicated Begin calls on the same batch instance.
- Use try/finally so End always runs after a successful Begin.
- Give each subsystem its own batch instance instead of sharing one.
Example fix
// before spriteBatch.Begin(mode, blend); spriteBatch.Begin(mode, blend); // throws // after spriteBatch.Begin(mode, blend); spriteBatch.End(); spriteBatch.Begin(mode, blend);
Defensive patterns
Strategy: try-catch
Validate before calling
if (isBatchActive) spriteBatch.End(); // close previous session first
Type guard
bool CanBegin(BatchBase b) => b != null && !isBatchActive;
Try / catch
try { spriteBatch.Begin(mode, blend); }
catch (InvalidOperationException ex) when (ex.Message.StartsWith("End must be called"))
{
spriteBatch.End();
spriteBatch.Begin(mode, blend);
} Prevention
- Never nest Begin calls on the same batch.
- Wrap End in finally after Begin.
- Give each subsystem its own batch.
When it happens
Trigger: Calling batch.Begin(...) twice in a row without an intervening End(); calling Begin from two systems in the same frame (e.g. UI and sprites sharing one SpriteBatch); a previous End() call throwing or being skipped by an early return.
Common situations: Two game subsystems both calling Begin on a shared SpriteBatch per frame; nested render callbacks that call Begin again inside an active batch; error paths that skip the End call leaving the flag set for the next 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
- Begin must be called before functionName
- Only one SpriteBatch at a time can use…
- Cannot end one SpriteBatch while another is using…
- Trying to serialize a Buffer without CPU info.
- Expecting texture input on slot
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/1fff704c7c36394a.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Graphics/BatchBase.cs:279
if (ResourceContext.VertexBuffer != null)
GraphicsContext.CommandList.SetVertexBuffer(0, ResourceContext.VertexBuffer, 0, vertexStructSize);
if (ResourceContext.IndexBuffer != null)
GraphicsContext.CommandList.SetIndexBuffer(ResourceContext.IndexBuffer, 0, indexStructSize == sizeof(int));
}
protected void CheckBeginHasBeenCalled(string functionName)
{
if (!isBeginCalled)
{
throw new InvalidOperationException("Begin must be called before " + functionName);
}
}
protected void CheckEndHasBeenCalled(string functionName)
{
if (isBeginCalled)
{
throw new InvalidOperationException("End must be called before " + functionName);
}
}
/// <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)View on GitHub (pinned to 96fad776d2)