Quick answer: AnimatorOverrideController clips fail to play when the original clip slot is null, the clip name does not match the base controller’s state, or the override is assigned to the Animator before all clips are populated. Verify every slot, match names exactly, and reassign the controller after runtime changes.

Here is how to fix Unity AnimatorOverrideController clips not playing. You set up an AnimatorOverrideController to swap animation clips at runtime — maybe to give different characters unique attack or idle animations while sharing the same state machine. But when you hit Play, the character stands frozen or plays the original base clip instead of the override. No errors, no warnings, just the wrong animation. This is one of the most frustrating silent failures in Unity’s animation system.

The Symptom

You have a base AnimatorController with states like Idle, Walk, and Attack. You create an AnimatorOverrideController that references this base controller and assign replacement clips for one or more states. When you assign the override controller to a character’s Animator component, the overridden states either play the original base clip, play nothing at all, or briefly flash the correct clip before reverting.

The problem often appears only on specific characters or only when clips are assigned at runtime. In the Inspector, the override controller looks correct — the right clips appear in the right slots. But the Animator window shows the state playing an empty or mismatched clip.

In some cases, the override works perfectly in the Editor but breaks in builds. Characters that animated correctly during development suddenly stand idle in the shipped game.

What Causes This

1. Null clip slots. This is the most common culprit. If any clip slot in the AnimatorOverrideController is left empty (null), Unity does not throw an error. It simply plays nothing for that state. The Animator enters the state, the state’s duration is zero because there is no clip, and it transitions out immediately. This looks like the animation "skipping" or never playing. Every slot must have a valid AnimationClip reference — even states you do not intend to override need their original clips preserved.

2. Clip name mismatch. The AnimatorOverrideController maps overrides by matching the AnimationClip asset reference used in the base controller, not the state name. If you rename a clip asset, delete and re-import it, or swap the clip in the base controller’s state, the override mapping breaks silently. The override controller still shows the old clip name in its list, but the mapping no longer connects to any state.

3. Runtime assignment timing. When you create or modify an AnimatorOverrideController at runtime, the order of operations matters. If you assign the override to animator.runtimeAnimatorController before populating all clip slots, the Animator binds to the incomplete override. Subsequent clip assignments do not automatically trigger a rebind. The Animator keeps playing whatever clips it had when the controller was first assigned.

4. Missing state names in code. When using the string-based indexer (overrideController["StateName"]), the string must match the original AnimationClip asset name, not the Animator state name. These are often different. A state named “Attack” might contain a clip named “sword_slash_01”. Using overrideController["Attack"] does nothing because no clip with that name exists in the base controller.

The Fix

Step 1: Audit all clip slots in the override controller. Open the AnimatorOverrideController in the Inspector and verify that every row has a clip assigned. If you see any empty slots, assign the original base clip to preserve that state’s animation.

Step 2: Use the correct clip names when assigning at runtime.

using UnityEngine;
using System.Collections.Generic;

public class CharacterSkinController : MonoBehaviour
{
    [SerializeField] private AnimatorOverrideController baseOverride;
    [SerializeField] private AnimationClip newIdleClip;
    [SerializeField] private AnimationClip newAttackClip;

    private Animator animator;

    void Start()
    {
        animator = GetComponent<Animator>();
        ApplyOverrides();
    }

    void ApplyOverrides()
    {
        // Create a runtime copy so we don’t modify the shared asset
        var runtimeOverride = new AnimatorOverrideController(baseOverride.runtimeAnimatorController);

        // Get ALL current override pairs from the base
        var overrides = new List<KeyValuePair<AnimationClip, AnimationClip>>();
        baseOverride.GetOverrides(overrides);

        // Log all available clip names for debugging
        foreach (var pair in overrides)
        {
            Debug.Log($"Original clip: {pair.Key.name} -> Override: {pair.Value?.name ?? "NULL"}");
        }

        // Assign new clips BEFORE setting the controller on the Animator
        runtimeOverride["idle_default"] = newIdleClip;     // Use the CLIP name, not state name
        runtimeOverride["attack_slash_01"] = newAttackClip;

        // Assign the fully-populated override controller last
        animator.runtimeAnimatorController = runtimeOverride;
    }
}

The key detail is populating every clip override before assigning the controller to the Animator. The GetOverrides call lets you inspect exactly which clip names the override controller expects, which eliminates guesswork.

Step 3: Force a rebind when changing clips on an already-assigned controller.

public void SwapAttackClip(AnimationClip newClip)
{
    var overrideController = animator.runtimeAnimatorController as AnimatorOverrideController;
    if (overrideController == null)
    {
        Debug.LogError("Animator is not using an AnimatorOverrideController.");
        return;
    }

    // Assign the new clip
    overrideController["attack_slash_01"] = newClip;

    // Force the Animator to rebind by reassigning the controller
    animator.runtimeAnimatorController = null;
    animator.runtimeAnimatorController = overrideController;

    // Alternatively, use Rebind() to force a full reset
    // animator.Rebind();
    // Warning: Rebind resets ALL state machine state to defaults
}

Setting runtimeAnimatorController to null and back is a well-known workaround that forces Unity to re-evaluate all clip bindings. The Rebind() method is more aggressive — it resets the entire state machine, which may not be desirable mid-gameplay.

Why This Works

Unity’s animation system caches clip bindings internally when an AnimatorController is assigned to an Animator. This caching is a performance optimization — rebinding clips every frame would be expensive. But it means that changes to clip mappings after the initial assignment are not automatically detected.

The AnimatorOverrideController was designed primarily as an authoring tool: you set up overrides in the Inspector and they are applied when the scene loads. Runtime modification was added later and requires the manual rebind step. This is a known friction point in Unity’s API, and the documentation does not emphasize it enough.

Null clip slots are silent because Unity treats them as “no animation for this state,” which is technically valid. A state with no clip has zero duration, so it enters and exits in a single frame. This is by design for blend trees that might have optional clips, but it is confusing when you expect a state to play something.

“Always log the output of GetOverrides when debugging AnimatorOverrideController issues. The clip names Unity expects are almost never what you think they are.”

Edge Cases to Watch

Shared override controller assets. If multiple characters reference the same AnimatorOverrideController asset and you modify it at runtime using the indexer, all characters sharing that asset are affected. Always create a runtime copy with new AnimatorOverrideController(baseController) when you need per-character overrides.

Addressables and asset bundles. Clips loaded asynchronously from Addressables may not be ready when the override controller is assigned. Ensure the AsyncOperationHandle completes before populating the override. Assigning a clip that is still loading results in a null reference that Unity does not report.

Blend trees. Override controllers can replace clips inside blend trees, but the clip name must still match the original clip used in the blend tree leaf, not the blend tree state name. Blend trees add a layer of indirection that makes name mismatches even more likely.

Related Issues

If the override controller is working but the Animator is not transitioning between states correctly, the problem may be in your transition conditions — see Animation Not Playing in Animator. If clips play but the character’s transform is not updated, check whether the animation clips are using the correct rig type — a Generic clip on a Humanoid avatar will apply no motion. See Coroutine Not Starting if your clip-swapping logic runs inside a coroutine that silently stops.

Call GetOverrides and log every clip name. The indexer string must match the clip asset name, not the Animator state name.