Skip to content
Loadout

Fix

Unity 6 Awaitable vs Task.Delay

Answer

In Unity 6, wait with Awaitable.WaitForSecondsAsync from the main thread, or use a coroutine. Thread.Sleep suspends the calling thread, so do not call it on the main thread. WaitForSecondsAsync can only be called from the main thread and always completes there. A destroyed MonoBehaviour acts as if it is null. Check this != null after an await, or pass a cached destroyCancellationToken.

  • Unity 6.3 LTS (6000.3.x), APIs checked against 6000.6 docs on 2026-10-15
  • Input System com.unity.inputsystem (Unity 6 new-project default)

Last verified 2026-10-15

Agents still paste Thread.Sleep or Task.Delay into a Unity 6 script and then touch a Transform. The Unity 6 pack is written to stop that paste. It is pinned to Unity 6.3 LTS (6000.3.x), APIs checked against 6000.6 docs on 2026-10-15. Obsolete Find calls are /fixes/unity-6-findobjectoftype-obsolete. Input.GetAxis is /fixes/unity-6-input-system-vs-input. .meta files and dotnet build are /fixes/unity-6-meta-files-and-dotnet-build. This page is the async and timing section of that rules file.

The pack prefers Awaitable, await Awaitable.WaitForSecondsAsync(1f), or a coroutine. Do not use Thread.Sleep or Task.Delay on the main thread. Thread.Sleep suspends the calling thread, so on the main thread it blocks that thread. WaitForSecondsAsync can only be called from the main thread and always completes there. A CancellationToken canceled during the wait throws OperationCanceledException and aborts the wait. Later lines run only if that exception is caught.

Awaitable is usually preferable to Task, and instances are pooled. Awaiting the same instance twice can result in an exception or a deadlock. Task.Delay does not suspend the thread. A Task started on the main thread resumes on the next frame Update through UnitySynchronizationContext, and Task has no update-loop scheduling. Awaitable does, through NextFrameAsync, FixedUpdateAsync, MainThreadAsync, and BackgroundThreadAsync. Those thread switches apply only in the method that calls them. Background work keeps running after Play mode exits. Cancel it with Application.exitCancellationToken.

Most Unity APIs can be called only from the main thread. Touch Transform, GameObject, and components only there. A destroyed MonoBehaviour acts as if it is null, so obj == null is true, while the null-conditional and null-coalescing operators are not supported. Check this != null after an await. Cache destroyCancellationToken before the object is destroyed and pass it to WaitForSecondsAsync. The token is raised on destroy. Checked against https://docs.unity3d.com/6000.3/Documentation/Manual/async-awaitable-introduction.html and https://docs.unity3d.com/6000.3/Documentation/ScriptReference/Awaitable.WaitForSecondsAsync.html.

Last verified 2026-10-15. doc-verified.

Pro

Unity 6 Pro rules, $1+

$1+ · pay what you want

Netcode for GameObjects, URP and Shader Graph, Addressables, and the Test Runner. Deeper than the free Unity 6 pack.

Each pack ships as AGENTS.md, CLAUDE.md, Cursor .mdc, and Copilot instructions, with 12 months of free updates.

From the Unity 6 Pro rules

Mark an RPC with `[Rpc(SendTo.Server)]` and end the method name in `Rpc`. A missing `Rpc` suffix is an error. Do not write new `[ServerRpc]` or `[ClientRpc]` methods.
A client asks the server with `SendTo.Server`. The server talks to observers with `SendTo.NotServer`, or `SendTo.ClientsAndHost` when a host must run the method too. There is no direct client-to-client connection. The server forwards it.
Keep shared state on a `NetworkVariable<T>` and use `.Value`. It is sent to clients already connected and to a client that joins later. An RPC is not. Write `.Value` from the server when write permission is `NetworkVariableWritePermission.Server`.
Put a `NetworkObject` on the networked prefab and spawn it on the server. Do not use the removed UNet types `NetworkIdentity`, `[Command]`, or `UnityEngine.Networking`.
Unity 6 Pro rules, $1+

Unity 6 pack — Unity 6 C# rules that avoid the obsolete 2022 APIs.

doc-verified

Sources in the pack

Docs

Questions

Should Unity 6 wait with Task.Delay or Awaitable?
In Unity 6, wait with Awaitable.WaitForSecondsAsync from the main thread, or use a coroutine. Thread.Sleep suspends the calling thread, so do not call it on the main thread. WaitForSecondsAsync can only be called from the main thread and always completes there. A destroyed MonoBehaviour acts as if it is null. Check this != null after an await, or pass a cached destroyCancellationToken.
Does Task.Delay block the Unity main thread?
No. Task.Delay does not suspend the thread. Thread.Sleep does. A Task started on the main thread resumes on the next frame Update through UnitySynchronizationContext. Awaitable.WaitForSecondsAsync can only be called from the main thread and always completes there.
What should I check after await in a Unity 6 MonoBehaviour?
A destroyed MonoBehaviour acts as if it is null, so check this != null. The null-conditional and null-coalescing operators are not supported. Cache destroyCancellationToken before the object is destroyed and pass it to WaitForSecondsAsync. Do not await the same Awaitable instance twice.
When was this Unity 6 Awaitable rule last checked?
Last verified 2026-10-15. doc-verified.