{"record":{"id":"fd5a3386bec29d5f","repo":"stride3d/stride","slug":"stack-should-end-up-with-result","errorCode":null,"errorMessage":"Stack should end up with result.","messagePattern":"Stack should end up with result\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Engine/Animations/AnimationBlender.cs","lineNumber":345,"sourceCode":"            else\n            {\n                result = AllocateIntermediateResult();\n            }\n\n            animationOperation0.Evaluator.Compute((CompressedTimeSpan)animationOperation0.Time, result);\n\n            animationStack.Push(result);\n\n            for (int index = 1; index < animationOperations.Count; index++)\n            {\n                var animationOperation = animationOperations[index];\n\n                ApplyAnimationOperation(ref animationOperation);\n            }\n\n            if (hasResult && (animationStack.Count != 1 || animationStack.Pop() != result))\n            {\n                throw new InvalidOperationException(\"Stack should end up with result.\");\n            }\n        }\n\n        private void ApplyAnimationOperation(ref AnimationOperation animationOperation)\n        {\n            switch (animationOperation.Type)\n            {\n                case AnimationOperationType.Blend:\n                    {\n                        // Blend stack[last - 1] and stack[last] into stack[last - 1], then pop stack[last]\n                        var op2 = animationStack.Pop();\n                        var op1 = animationStack.Peek();\n                        Blend(animationOperation.CoreBlendOperation, animationOperation.BlendFactor, op1, op2, op1);\n                        FreeIntermediateResult(op2);\n                    }\n                    break;\n                case AnimationOperationType.Push:\n                    {","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Engine/Animations/AnimationBlender.cs#L327-L363","documentation":"After applying all animation operations, ComputeAnimationBlending requires that, when a result buffer was supplied, the operation stack collapses to exactly one item that is the supplied result. If the stack has a different size or the final popped item is not the result object, the operation sequence was unbalanced and this InvalidOperationException is thrown at AnimationBlender.cs:345.","triggerScenarios":"Passing a non-null result plus an operation list that leaves the internal stack with 0 or >1 items, or whose final item is not the result — e.g. an extra Push, a missing final Pop, or mismatched Push/Pop counts.","commonSituations":"Hand-built AnimationOperation sequences with unbalanced Push/Pop pairs; animation graph code emitting a blend layer but forgetting the terminating Pop; two blender versions disagreeing on whether result is consumed from the stack.","solutions":["Audit the operation list so Push/Pop operations are balanced: one initial Push and exactly one Pop per subsequently pushed item, ending with the result.","Pass result = null if you don't require the stack to end with a specific buffer (the check only applies when hasResult is true).","Log each AnimationOperation before the call and simulate the stack to find the imbalance.","Check for Stride version mismatches between the code generating operations and the blender implementation."],"exampleFix":"// before\noperations.Add(new AnimationOperation { Type = AnimationOperationType.Push, ... });\n// missing Pop at the end\n\n// after\noperations.Add(new AnimationOperation { Type = AnimationOperationType.Push, ... });\noperations.Add(new AnimationOperation { Type = AnimationOperationType.Pop });","handlingStrategy":"validation","validationCode":"// Simulate stack balance before blending\nint depth = 0;\nforeach (var op in operations) {\n    if (op.Type == AnimationOperationType.Push) depth++;\n    else if (op.Type == AnimationOperationType.Pop) depth--;\n    if (depth < 0) throw new ArgumentException(\"Unbalanced operations: extra Pop\");\n}\nif (depth != 1) throw new ArgumentException(\"Operations must leave exactly the result on the stack\");","typeGuard":null,"tryCatchPattern":"try { blender.ComputeAnimationBlending(ops, ref result); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Stack should end up with result\")) { /* log ops and fix Push/Pop balance */ }","preventionTips":["Track Push/Pop counts when generating operations","Append a Pop for every Push beyond the first","Pass result=null when you don't need stack-end verification"],"tags":["animation","stack","invalid-state","blending"],"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-23T08:17:48.524Z"}