{"record":{"id":"c91c123da6a4c755","repo":"stride3d/stride","slug":"first-operation-should-be-a-push","errorCode":null,"errorMessage":"First operation should be a push","messagePattern":"First operation should be a push","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Engine/Animations/AnimationBlender.cs","lineNumber":306,"sourceCode":"                }\n            }\n        }\n\n        /// <summary>\n        /// Computes the specified animation operations.\n        /// </summary>\n        /// <param name=\"animationOperations\">The animation operations to perform.</param>\n        /// <param name=\"result\">The optional result (if not null, it expects the final stack to end up with this element).</param>\n        public void Compute(List<AnimationOperation> animationOperations, ref AnimationClipResult result)\n        {\n            // Clear animation stack\n            animationStack.Clear();\n\n            // Apply first operation (should be a push), directly into result (considered first item in the stack)\n            var animationOperation0 = animationOperations[0];\n\n            if (animationOperation0.Type != AnimationOperationType.Push)\n                throw new InvalidOperationException(\"First operation should be a push\");\n\n            // TODO: Either result is null (should have a Pop operation) or result is non null (stack end up being size 1)\n            var hasResult = result != null;\n            if (hasResult)\n            {\n                // Ensure there is enough size\n                // TODO: Force result allocation to happen on user side?\n                if (result.DataSize < structureSize)\n                {\n                    result.DataSize = structureSize;\n                    result.Data = new byte[structureSize];\n                }\n\n                if (objectsSize > 0 && (result.Objects == null || result.Objects.Length < objectsSize))\n                {\n                    result.Objects = new UpdateObjectData[objectsSize];\n                }\n","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Engine/Animations/AnimationBlender.cs#L288-L324","documentation":"AnimationBlender.ComputeAnimationBlending treats the animation operation list as stack machine instructions; the very first operation must be a Push that seeds the result. If animationOperations[0].Type is not AnimationOperationType.Push, the blender's invariants cannot hold and it throws this InvalidOperationException.","triggerScenarios":"Calling ComputeAnimationBlending with an operation list whose first entry is Pop, Blend, CheckTotal or any non-Push type — e.g. building the operation list manually or with an off-by-one that drops the initial Push at AnimationBlender.cs:306.","commonSituations":"Custom animation graph/tooling code constructing AnimationOperation lists by hand; truncated or incorrectly ordered operation sequences generated by an animation clip evaluator; rebasing/blending code emitting operations starting with a blend onto an empty stack.","solutions":["Ensure the operation list starts with an AnimationOperation of type Push (the base/first animation).","Fix the code that emits the operation sequence so the initial Push is never skipped.","Validate/normalize the operation list before calling ComputeAnimationBlending.","If the list can legitimately be empty, check animationOperations.Count > 0 and first type before invoking the blender."],"exampleFix":"// before\nblender.ComputeAnimationBlending(operations, ref result);\n\n// after (pre-validation)\nif (operations.Count == 0 || operations[0].Type != AnimationOperationType.Push)\n    throw new ArgumentException(\"Operations must start with a Push\");\nblender.ComputeAnimationBlending(operations, ref result);","handlingStrategy":"validation","validationCode":"// Guard before calling the blender\nif (operations == null || operations.Count == 0 || operations[0].Type != AnimationOperationType.Push)\n    throw new ArgumentException(\"Operation list must start with a Push\");","typeGuard":null,"tryCatchPattern":"try { blender.ComputeAnimationBlending(ops, ref result); }\ncatch (InvalidOperationException ex) when (ex.Message == \"First operation should be a push\") { /* rebuild op list starting with Push */ }","preventionTips":["Build operation lists via a helper that always emits an initial Push","Never slice an operation list starting at index > 0 without prepending a Push","Unit-test operation-sequence generators for ordering invariants"],"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"}