Unity-Technologies/UnityCsReference · error · ArgumentNullException

curves must be non-null

Error message

curves must be non-null

What it means

Thrown by AnimationUtility.SetEditorCurves when the curves array (AnimationCurve[]) is null. Singular SetEditorCurve accepts a null curve to delete that binding, but the batch form requires a non-null array so it can compare length with bindings and iterate. Guard order: bindings null, then curves null, then length mismatch.

Source

Thrown at Editor/Mono/Animation/AnimationUtility.bindings.cs:282

        }

        [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);
        }

View on GitHub (pinned to 225b0fbdb5)

Solutions

  1. Default to Array.Empty<AnimationCurve>() instead of null when no curves exist.
  2. If you mean to delete curves, pass non-null array of nulls (one per binding) or use the singular API per binding.
  3. Build curves and bindings in one pass.
  4. Validate at the boundary before calling.

Example fix

// before
var curves = hasData ? BuildCurves() : null;
AnimationUtility.SetEditorCurves(clip, bindings, curves);

// after
var curves = hasData ? BuildCurves() : Array.Empty<AnimationCurve>();
AnimationUtility.SetEditorCurves(clip, bindings, curves);
Defensive patterns

Strategy: validation

Validate before calling

if (curves == null) curves = Array.Empty<AnimationCurve>();

Prevention

When it happens

Trigger: Calling SetEditorCurves(clip, bindings, null). A curve builder that returns null for 'no curves'. Reusing the singular API's null-means-delete semantics in the plural API.

Common situations: Programmatic clip generation defaulting curves to null. Serialization round-trips where an empty curves array came back as null. Copying from SetEditorCurve singular usage.

Related errors


AI-assisted analysis of Unity-Technologies/UnityCsReference@225b0fbdb5 (2026-08-13). Data as JSON: /api/errors/275cb408ded9980b. Report an issue: GitHub.