Unity-Technologies/UnityCsReference · error · InvalidOperationException
bindings and keyframes must be of equal length
Error message
bindings and keyframes must be of equal length
What it means
Thrown by AnimationUtility.SetObjectReferenceCurves when bindings.Length != keyframes.Length. The batch API zips the two arrays element-wise; a length mismatch would either leave bindings un-synced or index out of range, so it throws InvalidOperationException before the loop and the final SyncEditorCurves.
Source
Thrown at Editor/Mono/Animation/AnimationUtility.bindings.cs:249
extern public static EditorCurveBinding[] GetCurveBindings([NotNull] AnimationClip clip);
extern public static EditorCurveBinding[] GetObjectReferenceCurveBindings([NotNull] AnimationClip clip);
extern public static ObjectReferenceKeyframe[] GetObjectReferenceCurve([NotNull] AnimationClip clip, EditorCurveBinding binding);
public static void SetObjectReferenceCurve(AnimationClip clip, EditorCurveBinding binding, ObjectReferenceKeyframe[] keyframes)
{
Internal_SetObjectReferenceCurve(clip, binding, keyframes, true);
Internal_InvokeOnCurveWasModified(clip, binding, keyframes != null ? CurveModifiedType.CurveModified : CurveModifiedType.CurveDeleted);
}
public static void SetObjectReferenceCurves(AnimationClip clip, EditorCurveBinding[] bindings, ObjectReferenceKeyframe[][] keyframes)
{
if (bindings == null)
throw new ArgumentNullException(nameof(bindings), $"{nameof(bindings)} must be non-null");
if (keyframes == null)
throw new ArgumentNullException(nameof(keyframes), $"{nameof(keyframes)} must be non-null");
if (bindings.Length != keyframes.Length)
throw new InvalidOperationException($"{nameof(bindings)} and {nameof(keyframes)} must be of equal length");
int length = bindings.Length;
for (int i = 0; i < length; i++)
{
SetObjectReferenceCurveNoSync(clip, bindings[i], keyframes[i]);
}
SyncEditorCurves(clip);
Internal_InvokeOnCurveWasModified(clip, new EditorCurveBinding(), CurveModifiedType.ClipModified);
}
internal static void SetObjectReferenceCurveNoSync(AnimationClip clip, EditorCurveBinding binding, ObjectReferenceKeyframe[] keyframes)
{
Internal_SetObjectReferenceCurve(clip, binding, keyframes, false);
Internal_InvokeOnCurveWasModified(clip, binding, keyframes != null ? CurveModifiedType.CurveModified : CurveModifiedType.CurveDeleted);
}
[NativeMethod(ThrowsException = true)]
extern private static void Internal_SetObjectReferenceCurve([NotNull] AnimationClip clip, EditorCurveBinding binding, ObjectReferenceKeyframe[] keyframes, bool updateMuscleClip);View on GitHub (pinned to 225b0fbdb5)
Solutions
- Assert Debug.Assert(bindings.Length == keyframes.Length, context) at construction.
- Build bindings and keyframes together in one pass so they cannot diverge.
- Add a length-check helper and call it before every Set*Curves invocation.
- If lengths legitimately differ, zip to the shorter length explicitly and document why.
Example fix
// before
AnimationUtility.SetObjectReferenceCurves(clip, bindings, keyframes); // mismatched lengths
// after
if (bindings.Length != keyframes.Length)
throw new InvalidOperationException($"bindings({bindings.Length}) != keyframes({keyframes.Length}) for {clip.name}");
AnimationUtility.SetObjectReferenceCurves(clip, bindings, keyframes); Defensive patterns
Strategy: validation
Validate before calling
if (bindings.Length != keyframes.Length) throw new InvalidOperationException($"bindings({bindings.Length}) != keyframes({keyframes.Length})"); Prevention
- Build both arrays in one loop so lengths cannot diverge.
- Assert length equality at construction with a context message.
- Filter both arrays together, never independently.
When it happens
Trigger: Bindings built from one set of properties and keyframes from another. A jagged keyframes array built by pushing one entry per clip but bindings built per-property. Removing an element from one array and forgetting the other.
Common situations: Migrating clips between rigs where property bindings change count. Timeline/Animator tooling that filters keyframes after building bindings. Code that appends to one list in a loop but not the other.
Related errors
- bindings and curves must be of equal length
- gameObject
- bindings must be non-null
- keyframes must be non-null
- curves must be non-null
AI-assisted analysis of Unity-Technologies/UnityCsReference@225b0fbdb5 (2026-08-13).
Data as JSON: /api/errors/e28e54e3393fae80.
Report an issue: GitHub.