Unity-Technologies/UnityCsReference · error · InvalidOperationException
bindings and curves must be of equal length
Error message
bindings and curves must be of equal length
What it means
Thrown by AnimationUtility.SetEditorCurves when bindings.Length != curves.Length. The batch API iterates both in lockstep and calls SetEditorCurveNoSync per index; a mismatch would desync or index out of range, so it throws InvalidOperationException before the loop.
Source
Thrown at Editor/Mono/Animation/AnimationUtility.bindings.cs:284
[NativeMethod(ThrowsException = true)]
extern private static void Internal_SetObjectReferenceCurve([NotNull] AnimationClip clip, EditorCurveBinding binding, ObjectReferenceKeyframe[] keyframes, bool updateMuscleClip);
extern public static AnimationCurve GetEditorCurve([NotNull] AnimationClip clip, EditorCurveBinding binding);
public static void SetEditorCurve(AnimationClip clip, EditorCurveBinding binding, AnimationCurve curve)
{
Internal_SetEditorCurve(clip, binding, curve, true);
Internal_InvokeOnCurveWasModified(clip, binding, curve != null ? CurveModifiedType.CurveModified : CurveModifiedType.CurveDeleted);
}
public static void SetEditorCurves(AnimationClip clip, EditorCurveBinding[] bindings, AnimationCurve[] curves)
{
if (bindings == null)
throw new ArgumentNullException(nameof(bindings), $"{nameof(bindings)} must be non-null");
if (curves == null)
throw new ArgumentNullException(nameof(curves), $"{nameof(curves)} must be non-null");
if (bindings.Length != curves.Length)
throw new InvalidOperationException($"{nameof(bindings)} and {nameof(curves)} must be of equal length");
int length = bindings.Length;
for (int i = 0; i < length; i++)
{
SetEditorCurveNoSync(clip, bindings[i], curves[i]);
}
SyncEditorCurves(clip);
Internal_InvokeOnCurveWasModified(clip, new EditorCurveBinding(), AnimationUtility.CurveModifiedType.ClipModified);
}
internal static void SetEditorCurveNoSync(AnimationClip clip, EditorCurveBinding binding, AnimationCurve curve)
{
Internal_SetEditorCurve(clip, binding, curve, false);
Internal_InvokeOnCurveWasModified(clip, binding, curve != null ? CurveModifiedType.CurveModified : CurveModifiedType.CurveDeleted);
}
[NativeMethod(ThrowsException = true)]View on GitHub (pinned to 225b0fbdb5)
Solutions
- Assert bindings.Length == curves.Length with a context message at build time.
- Construct both arrays in a single pass so they stay paired.
- Run a length-equality check helper before every Set*Curves call.
- If they legitimately differ, zip to the shorter and log the dropped entries.
Example fix
// before
AnimationUtility.SetEditorCurves(clip, bindings, curves);
// after
if (bindings.Length != curves.Length)
throw new InvalidOperationException($"bindings({bindings.Length}) != curves({curves.Length}) on {clip.name}");
AnimationUtility.SetEditorCurves(clip, bindings, curves); Defensive patterns
Strategy: validation
Validate before calling
if (bindings.Length != curves.Length) throw new InvalidOperationException($"bindings({bindings.Length}) != curves({curves.Length})"); Prevention
- Construct bindings and curves in a single paired pass.
- Assert length equality with clip context for diagnostics.
- Never filter one array without mirroring the other.
When it happens
Trigger: Bindings built per-property and curves built per-clip, or vice versa. Filtering one array after building the other. Appending a curve for a new property but forgetting its binding.
Common situations: Rig migration where binding count changes. Editor tools that filter curves after constructing bindings. Copy-paste loops that increment one list conditionally.
Related errors
- bindings and keyframes 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/73ccadbc7961484d.
Report an issue: GitHub.