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
- Add all curves before freezing the clip (set Frozen only after clip construction is complete).
- Create a new unfrozen AnimationClip, copy the curves into it, add the new curve, and use that clip instead.
- If you own the lifecycle and know the clip isn't in use, temporarily set Frozen = false, add the curve, then re-freeze.
- 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
- Freeze clips only after all curves are added
- Treat frozen clips as read-only and copy before extending
- Centralize clip mutation behind a helper that checks Frozen
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
- First operation should be a push
- Stack should end up with result.
- Trying to await end of an animation which is not playing
- A disposed operation cannot be rollbacked.
- A disposed operation cannot be rollforwarded.
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)