stride3d/stride · error · InvalidOperationException

This AnimationClip is frozen

Error message

This AnimationClip is frozen

What it means

AnimationClip.Frozen marks a clip as immutable (typically after baking/optimization for runtime use). AddCurve checks Frozen first and throws this InvalidOperationException rather than mutating a frozen clip, since adding channels after freezing would invalidate precomputed curve data.

Solutions

  1. Add all curves before freezing the clip (set Frozen only after clip construction is complete).
  2. Create a new unfrozen AnimationClip, copy the curves into it, add the new curve, and use that clip instead.
  3. If you own the lifecycle and know the clip isn't in use, temporarily set Frozen = false, add the curve, then re-freeze.
  4. Check callers like Start/SubtractAnimations/ExportAnimation that operate on already-frozen clips and clone first.

Example fix

// before
myClip.AddCurve("Base[Node].Scale", curve); // throws: clip is frozen

// after
if (!myClip.Frozen)
    myClip.AddCurve("Base[Node].Scale", curve);
else {
    var newClip = new AnimationClip();
    // copy channels from myClip, then:
    newClip.AddCurve("Base[Node].Scale", curve);
}
Defensive patterns

Strategy: validation

Validate before calling

// Check before mutating
if (clip.Frozen)
    throw new InvalidOperationException("Cannot AddCurve on a frozen AnimationClip; create a copy first");
clip.AddCurve(propertyName, curve);

Try / catch

try { clip.AddCurve(name, curve); }
catch (InvalidOperationException ex) when (ex.Message == "This AnimationClip is frozen") { /* clone clip, add curve to the clone */ }

Prevention

When it happens

Trigger: Calling clip.AddCurve(propertyName, curve) on a clip whose Frozen property is true — e.g. modifying a clip after it was frozen by the animation system or by explicitly setting Frozen, at AnimationClip.cs:68.

Common situations: Procedurally extending an animation clip at runtime after it has been optimized/frozen; editing a clip asset already loaded and frozen by the engine; game code reusing a shared frozen clip to add per-entity curves.

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


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/9a25baac566926a0. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Engine/Animations/AnimationClip.cs:68

        public List<AnimationCurve> Curves = new List<AnimationCurve>();

        public AnimationData[] OptimizedAnimationDatas;

        /// <summary>
        /// Set this flag to true when the channel information of the clip have changed and need to be rescan by engine.
        /// </summary>
        [DataMemberIgnore]
        public bool ShouldRescanChannels;

        /// <summary>
        /// Adds a named curve.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="curve">The curve.</param>
        public void AddCurve(string propertyName, AnimationCurve curve, bool isUserCustomProperty = false)
        {
            if (Frozen)
                throw new InvalidOperationException("This AnimationClip is frozen");

            // Add channel
            Channels.Add(propertyName, new Channel
            {
                PropertyName = propertyName,
                CurveIndex = Curves.Count,
                ElementType = curve.ElementType,
                ElementSize = curve.ElementSize,
                IsUserCustomProperty = isUserCustomProperty,
            });
            Curves.Add(curve);
        }

        public AnimationCurve GetCurve(string propertyName)
        {
            Channel channel;
            if (!Channels.TryGetValue(propertyName, out channel))
                return null;

View on GitHub (pinned to 96fad776d2)