{"record":{"id":"152b9126086ef592","repo":"Cysharp/UniTask","slug":"asyncsubject-is-not-completed-yet","errorCode":null,"errorMessage":"AsyncSubject is not completed yet","messagePattern":"AsyncSubject is not completed yet","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/UniTask/Assets/Plugins/UniTask/Runtime/UniTaskObservableExtensions.cs","lineNumber":380,"sourceCode":"    }\n\n    internal sealed class AsyncSubject<T> : IObservable<T>, IObserver<T>\n    {\n        object observerLock = new object();\n\n        T lastValue;\n        bool hasValue;\n        bool isStopped;\n        bool isDisposed;\n        Exception lastError;\n        IObserver<T> outObserver = EmptyObserver<T>.Instance;\n\n        public T Value\n        {\n            get\n            {\n                ThrowIfDisposed();\n                if (!isStopped) throw new InvalidOperationException(\"AsyncSubject is not completed yet\");\n                if (lastError != null) ExceptionDispatchInfo.Capture(lastError).Throw();\n                return lastValue;\n            }\n        }\n\n        public bool HasObservers\n        {\n            get\n            {\n                return !(outObserver is EmptyObserver<T>) && !isStopped && !isDisposed;\n            }\n        }\n\n        public bool IsCompleted { get { return isStopped; } }\n\n        public void OnCompleted()\n        {\n            IObserver<T> old;","sourceCodeStart":362,"sourceCodeEnd":398,"githubUrl":"https://github.com/Cysharp/UniTask/blob/ceac8d6946b1125fe782cd171fbcb245b567dbf9/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTaskObservableExtensions.cs#L362-L398","documentation":"Thrown by the AsyncSubject<T>.Value getter (line 380) when isStopped is false. UniTask returns an internal AsyncSubject<T> from UniTask<T>.ToObservable() as the Rx bridge; like the Rx AsyncSubject it caches only the last value and publishes it on completion, so reading Value before the source task has finished is a contract violation (InvalidOperationException). The subject only becomes readable after Fire() calls OnNext + OnCompleted.","triggerScenarios":"Accessing the .Value property of the observable returned by someUniTask.ToObservable() before the underlying UniTask<T> has awaited to completion (i.e. isStopped still false). Happens when code casts the IObservable back to AsyncSubject<T> (or reaches the getter) and reads it synchronously while the producing task is still in flight.","commonSituations":"Polling a converted observable's value from a non-async/synchronous caller; a race where the producing task is slow and Value is read immediately after ToObservable() returns; mistaking the IObservable for an already-resolved value box.","solutions":["Check subject.IsCompleted before reading .Value (the getter only returns once isStopped is true).","Await the original UniTask<T> directly instead of reading the observable's Value.","Use .Subscribe(observer) or .ToUniTask() to receive the value asynchronously rather than reading it eagerly."],"exampleFix":"// before\nvar obs = myTask.ToObservable();\nvar v = ((AsyncSubject<int>)obs).Value; // throws: task not done\n\n// after\nvar v = await myTask; // await the source directly","handlingStrategy":"validation","validationCode":"// AsyncSubject<T>.IsCompleted maps to isStopped; check before reading Value\nvar subject = (AsyncSubject<int>)myTask.ToObservable();\nif (subject.IsCompleted) {\n    var v = subject.Value;\n} else {\n    // not ready; await the source instead\n}","typeGuard":null,"tryCatchPattern":"try {\n    var v = subject.Value;\n} catch (InvalidOperationException) {\n    // AsyncSubject not completed yet; await the source instead\n}","preventionTips":["Prefer awaiting the original UniTask<T> over reading the AsyncSubject's Value.","Always gate .Value access behind an IsCompleted check.","Treat ToObservable() output as a stream to subscribe to, not a synchronous value box."],"tags":["async","observable","invalidoperation","unitask","rx"],"backgroundTag":null,"analyzedSha":"ceac8d6946b1125fe782cd171fbcb245b567dbf9","analyzedAt":"2026-08-13T19:16:39.025Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}