{"record":{"id":"862af9c2a20f5c0d","repo":"Cysharp/UniTask","slug":"token-version-is-not-matched-can-not-await-twice","errorCode":null,"errorMessage":"Token version is not matched, can not await twice or get Status after await.","messagePattern":"Token version is not matched, can not await twice or get Status after await\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/UniTask/Assets/Plugins/UniTask/Runtime/UniTaskCompletionSource.cs","lineNumber":304,"sourceCode":"            {\n                // already running continuation in TrySet.\n                // It will cause call OnCompleted multiple time, invalid.\n                if (!ReferenceEquals(oldContinuation, UniTaskCompletionSourceCoreShared.s_sentinel))\n                {\n                    throw new InvalidOperationException(\"Already continuation registered, can not await twice or get Status after await.\");\n                }\n\n                continuation(state);\n            }\n        }\n\n        [DebuggerHidden]\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private void ValidateToken(short token)\n        {\n            if (token != version)\n            {\n                throw new InvalidOperationException(\"Token version is not matched, can not await twice or get Status after await.\");\n            }\n        }\n    }\n\n    internal static class UniTaskCompletionSourceCoreShared // separated out of generic to avoid unnecessary duplication\n    {\n        internal static readonly Action<object> s_sentinel = CompletionSentinel;\n\n        private static void CompletionSentinel(object _) // named method to aid debugging\n        {\n            throw new InvalidOperationException(\"The sentinel delegate should never be invoked.\");\n        }\n    }\n\n    public class AutoResetUniTaskCompletionSource : IUniTaskSource, ITaskPoolNode<AutoResetUniTaskCompletionSource>, IPromise\n    {\n        static TaskPool<AutoResetUniTaskCompletionSource> pool;\n        AutoResetUniTaskCompletionSource nextNode;","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/Cysharp/UniTask/blob/ceac8d6946b1125fe782cd171fbcb245b567dbf9/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTaskCompletionSource.cs#L286-L322","documentation":"Thrown by UniTaskCompletionSourceCore<TResult>.ValidateToken when the provided token does not match the current version. UniTask sources use a version (short token) to detect reuse after pooling or reset; an old token from a previous lifecycle is invalid. This typically indicates the UniTask was awaited or inspected after its source was recycled.","triggerScenarios":"Holding a UniTask and its token across a source reset/pool return, then calling GetResult/GetStatus/OnCompleted with the stale token. Awaiting a UniTask whose source has already been returned to the pool from a prior await.","commonSituations":"Awaiting a UniTask twice (second await uses a stale token after pool return). Caching a UniTask field that is reused across frames where the underlying source is pooled. Custom code that stores the token from a pooled source and uses it later.","solutions":["Await each UniTask exactly once and immediately","Do not cache UniTask or its token across frames; await it where it is created","If you need a reusable awaitable, use UniTaskCompletionSource (not pooled) or AutoResetUniTaskCompletionSource with proper lifecycle management","Ensure you do not call GetResult/GetStatus after the task has been consumed"],"exampleFix":"// before\nvar task = source.Task;\nawait task;\nvar status = task.GetStatus(oldToken); // throws: token mismatch\n\n// after\nvar task = source.Task;\nawait task;\n// do not touch the task after await","handlingStrategy":"validation","validationCode":"// Ensure token is current before use\n// In practice: never hold a UniTask across pool resets\n// Always await exactly once where the UniTask is created","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Await each UniTask exactly once immediately after creation","Never cache UniTask or its token beyond the first await","For reusable awaitables, use non-pooled UniTaskCompletionSource","Audit custom code that stores short tokens for later use"],"tags":["unitask","completion-source","token-validation","single-use","unity","csharp"],"backgroundTag":null,"analyzedSha":"ceac8d6946b1125fe782cd171fbcb245b567dbf9","analyzedAt":"2026-08-13T19:16:39.025Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}