Quick answer: The 0.9 cap is by design. With allowSceneActivation = false, the operation pauses at 90% waiting for permission to activate. Map your UI to progress / 0.9f so it shows 0–100%, then set activation true on user input.

Here is how to fix Unity scene loading that appears stuck forever at 90%. SceneManager.LoadSceneAsync with allowSceneActivation = false intentionally pauses to let you display a “Press any key to continue” prompt. Mapping the progress range correctly produces a clean 100% loading bar.

The Symptom

Loading bar fills to 90% and stays there. Player thinks the game is frozen. Setting allowSceneActivation = true jumps directly to the new scene without further progress display.

What Causes This

0.9 is the loading-only cap. The remaining 10% is the activation step: integrating the loaded scene, calling Awake/OnEnable on objects. With activation gated, the operation parks at 0.9.

Showing raw progress. Player sees 90% and assumes a hang.

No prompt for activation. Without UI letting players initiate activation, the loaded scene never appears.

The Fix

Step 1: Map progress 0–0.9 to 0–1.

using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class SceneLoader : MonoBehaviour
{
    [SerializeField] private Slider progressBar;
    [SerializeField] private GameObject pressAnyKeyHint;

    public IEnumerator LoadScene(string name)
    {
        AsyncOperation op = SceneManager.LoadSceneAsync(name);
        op.allowSceneActivation = false;

        while (op.progress < 0.9f)
        {
            progressBar.value = op.progress / 0.9f;
            yield return null;
        }

        progressBar.value = 1f;
        pressAnyKeyHint.SetActive(true);

        while (!Input.anyKeyDown) yield return null;

        op.allowSceneActivation = true;
        while (!op.isDone) yield return null;
    }
}

Step 2: For instant activation, leave allowSceneActivation default. If you do not need a Press Any Key prompt, do not set allowSceneActivation = false. Default true causes activation as soon as loading reaches 0.9, then progresses through 1.0.

Step 3: For multiple scenes, additive load.

AsyncOperation a = SceneManager.LoadSceneAsync("World", LoadSceneMode.Additive);
AsyncOperation b = SceneManager.LoadSceneAsync("UI", LoadSceneMode.Additive);
while (!a.isDone || !b.isDone) yield return null;

Each operation tracks its own progress.

Step 4: For Unity 2023+ async/await syntax.

async Awaitable LoadAsync(string name)
{
    var op = SceneManager.LoadSceneAsync(name);
    op.allowSceneActivation = false;
    while (op.progress < 0.9f)
    {
        progressBar.value = op.progress / 0.9f;
        await Awaitable.NextFrameAsync();
    }
    op.allowSceneActivation = true;
}

“0.9 cap is by design. Map progress / 0.9 to your UI. Press Any Key prompt makes the cap a feature, not a bug.”

Related Issues

For async scene callback issues, see Async Scene Loading Callbacks. For async/await deadlocks, see async/await Deadlock.

Map 0-0.9 to 0-1. Press Any Key to activate. The bar reaches 100%.