Cysharp/UniTask · error · InvalidOperationException

Already continuation registered, can not await twice or get

Error message

Already continuation registered, can not await twice or get Status after await.

What it means

Thrown by UniTaskCompletionSourceCore<TResult>.OnCompleted when a continuation is already registered and it is not the internal sentinel. UniTask structs are single-await by design: awaiting the same UniTask twice, or calling GetStatus/OnCompleted after awaiting, is invalid because the underlying source may have been returned to a pool. The guard detects double-registration of continuations.

Source

Thrown at src/UniTask/Assets/Plugins/UniTask/Runtime/UniTaskCompletionSource.cs:291

                C.1: win OnCompleted -> TrySet invoke saved continuation
                C.2: win TrySet -> should invoke continuation here.
            */

            // not set continuation yet.
            object oldContinuation = this.continuation;
            if (oldContinuation == null)
            {
                continuationState = state;
                oldContinuation = Interlocked.CompareExchange(ref this.continuation, continuation, null);
            }

            if (oldContinuation != null)
            {
                // already running continuation in TrySet.
                // It will cause call OnCompleted multiple time, invalid.
                if (!ReferenceEquals(oldContinuation, UniTaskCompletionSourceCoreShared.s_sentinel))
                {
                    throw new InvalidOperationException("Already continuation registered, can not await twice or get Status after await.");
                }

                continuation(state);
            }
        }

        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void ValidateToken(short token)
        {
            if (token != version)
            {
                throw new InvalidOperationException("Token version is not matched, can not await twice or get Status after await.");
            }
        }
    }

    internal static class UniTaskCompletionSourceCoreShared // separated out of generic to avoid unnecessary duplication

View on GitHub (pinned to ceac8d6946)

Solutions

  1. Await each UniTask exactly once; create a new UniTask for repeated operations
  2. If you need multiple consumers, use UniTaskCompletionSource and expose Task multiple times, or broadcast via IUniTaskAsyncEnumerable
  3. Never call GetStatus or OnCompleted on a UniTask after it has been awaited
  4. Avoid storing UniTask in long-lived fields; await it immediately or convert to a re-awaitable source

Example fix

// before
var task = DoSomethingAsync();
await task;
await task; // throws: already awaited

// after
await DoSomethingAsync();
await DoSomethingAsync(); // create a new task each time
Defensive patterns

Strategy: validation

Validate before calling

// UniTask is single-await; ensure you only await once
// If you need multi-consumer, use UniTaskCompletionSource:
var ucs = UniTaskCompletionSource.Create();
ucs.TrySetResult();
// ucs.Task can be awaited multiple times via separate UniTask instances

Prevention

When it happens

Trigger: Awaiting the same UniTask variable twice. Calling GetStatus after await on the same UniTask. Storing a UniTask in a field and awaiting it from multiple call sites. Pooling issues where a returned UniTaskCompletionSourceCore is reused while a stale continuation is still registered.

Common situations: Storing a UniTask and awaiting it in a loop or retry logic. Passing a UniTask to multiple consumers. Debugging code that inspects status after the task has already been awaited. Misusing pooled AutoResetUniTaskCompletionSource.

Related errors


AI-assisted analysis of Cysharp/UniTask@ceac8d6946 (2026-08-13). Data as JSON: /api/errors/9c2aa4c1b4e002b6. Report an issue: GitHub.