{"record":{"id":"1fff704c7c36394a","repo":"stride3d/stride","slug":"end-must-be-called-before-functionname","errorCode":null,"errorMessage":"End must be called before functionName","messagePattern":"End must be called before functionName","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Graphics/BatchBase.cs","lineNumber":279,"sourceCode":"            if (ResourceContext.VertexBuffer != null)\n                GraphicsContext.CommandList.SetVertexBuffer(0, ResourceContext.VertexBuffer, 0, vertexStructSize);\n            if (ResourceContext.IndexBuffer != null)\n                GraphicsContext.CommandList.SetIndexBuffer(ResourceContext.IndexBuffer, 0, indexStructSize == sizeof(int));\n        }\n\n        protected void CheckBeginHasBeenCalled(string functionName)\n        {\n            if (!isBeginCalled)\n            {\n                throw new InvalidOperationException(\"Begin must be called before \" + functionName);\n            }\n        }\n\n        protected void CheckEndHasBeenCalled(string functionName)\n        {\n            if (isBeginCalled)\n            {\n                throw new InvalidOperationException(\"End must be called before \" + functionName);\n            }\n        }\n\n        /// <summary>\n        /// Flushes the sprite batch and restores the device state to how it was before Begin was called.\n        /// </summary>\n        public void End()\n        {\n            CheckBeginHasBeenCalled(\"End\");\n\n            if (sortMode == SpriteSortMode.Immediate)\n            {\n                ResourceContext.IsInImmediateMode = false;\n            }\n            else if (drawsQueueCount > 0)\n            {\n                // Draw the queued sprites now.\n                if (ResourceContext.IsInImmediateMode)","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Graphics/BatchBase.cs#L261-L297","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nspriteBatch.Begin(mode, blend);\nspriteBatch.Begin(mode, blend); // throws\n// after\nspriteBatch.Begin(mode, blend);\nspriteBatch.End();\nspriteBatch.Begin(mode, blend);","handlingStrategy":"try-catch","validationCode":"if (isBatchActive) spriteBatch.End(); // close previous session first","typeGuard":"bool CanBegin(BatchBase b) => b != null && !isBatchActive;","tryCatchPattern":"try { spriteBatch.Begin(mode, blend); }\ncatch (InvalidOperationException ex) when (ex.Message.StartsWith(\"End must be called\"))\n{\n    spriteBatch.End();\n    spriteBatch.Begin(mode, blend);\n}","preventionTips":["Never nest Begin calls on the same batch.","Wrap End in finally after Begin.","Give each subsystem its own batch."],"tags":["graphics","rendering","invalid-state","spritebatch"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}