stride3d/stride · error · InvalidOperationException
Stack should end up with result.
Error message
Stack should end up with result.
What it means
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.
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.
Example fix
// before
operations.Add(new AnimationOperation { Type = AnimationOperationType.Push, ... });
// missing Pop at the end
// after
operations.Add(new AnimationOperation { Type = AnimationOperationType.Push, ... });
operations.Add(new AnimationOperation { Type = AnimationOperationType.Pop }); Defensive patterns
Strategy: validation
Validate before calling
// Simulate stack balance before blending
int depth = 0;
foreach (var op in operations) {
if (op.Type == AnimationOperationType.Push) depth++;
else if (op.Type == AnimationOperationType.Pop) depth--;
if (depth < 0) throw new ArgumentException("Unbalanced operations: extra Pop");
}
if (depth != 1) throw new ArgumentException("Operations must leave exactly the result on the stack"); Try / catch
try { blender.ComputeAnimationBlending(ops, ref result); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Stack should end up with result")) { /* log ops and fix Push/Pop balance */ } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
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
- First operation should be a push
- blendOperation
- This AnimationClip is frozen
- Trying to await end of an animation which is not playing
- A disposed operation cannot be rollbacked.
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/fd5a3386bec29d5f.
Report an issue: GitHub.
Appendix: source
Thrown at sources/engine/Stride.Engine/Animations/AnimationBlender.cs:345
else
{
result = AllocateIntermediateResult();
}
animationOperation0.Evaluator.Compute((CompressedTimeSpan)animationOperation0.Time, result);
animationStack.Push(result);
for (int index = 1; index < animationOperations.Count; index++)
{
var animationOperation = animationOperations[index];
ApplyAnimationOperation(ref animationOperation);
}
if (hasResult && (animationStack.Count != 1 || animationStack.Pop() != result))
{
throw new InvalidOperationException("Stack should end up with result.");
}
}
private void ApplyAnimationOperation(ref AnimationOperation animationOperation)
{
switch (animationOperation.Type)
{
case AnimationOperationType.Blend:
{
// Blend stack[last - 1] and stack[last] into stack[last - 1], then pop stack[last]
var op2 = animationStack.Pop();
var op1 = animationStack.Peek();
Blend(animationOperation.CoreBlendOperation, animationOperation.BlendFactor, op1, op2, op1);
FreeIntermediateResult(op2);
}
break;
case AnimationOperationType.Push:
{View on GitHub (pinned to 96fad776d2)