Skip to content

Fix AsUniTask returns Pending task when it should be completed - #731

Open
nandos13 wants to merge 4 commits into
Cysharp:masterfrom
nandos13:fix/asunitask-completed-task
Open

nandos13 wants to merge 4 commits into
Cysharp:masterfrom
nandos13:fix/asunitask-completed-task

Conversation

@nandos13

@nandos13 nandos13 commented Oct 9, 2026

Copy link
Copy Markdown

Fixes #730

Both the generic and non-generic overloads for the AsUniTask method now have a switch on task.Status and returns a completed UniTask if the input task is in the Canceled, Faulted or RanToCompletion state.
Unit tests have been added for these already-completed cases. I also improved test coverage for some missing cases where a Task completes after the AsUniTask call. These tests pass both before and after my fix changes.

Note that this is a behavioral change, a completed Task no longer forces a yield. This might cause problems if code leaned on the yield, but I believe this is now correct behavior.

Thanks

Added AsUniTask test cases for completed tasks (successful + faulted)
Added AsUniTask test cases for canceled tasks
Added regression test cases to make sure pending tasks are in the correct state before & after await, and carries the expected result. These tests should also pass without my changes, I noticed there were no test cases for these methods.
@timcassell

Copy link
Copy Markdown

Wouldn't it be much simpler to just await it?

public static async UniTask<T> AsUniTask<T>(this Task<T> task, bool useCurrentSynchronizationContext = true)
    => await task.ConfigureAwait(useCurrentSynchronizationContext);

@nandos13

nandos13 commented Oct 9, 2026

Copy link
Copy Markdown
Author

@timcassell
Your suggestion looks simpler and does seem to fix the already-completed case, but I found it does change some behavior. When a Task is still pending at the call, the returned UniTask becomes single use.

  • The current AsUniTask implementation returns a UniTask backed by UniTaskCompletionSource, which the README says "can await multiple times and await from many callers".
  • The UniTask returned by an async UniTask method that had to wait can only be awaited once, and a second await throws.

This test passes on master and with this PR, but it fails with the await version:

[Fact]
public async Task AsUniTask_PendingTaskWithResult_CanBeAwaitedTwice()
{
    var source = new TaskCompletionSource<int>();

    UniTask<int> task = source.Task.AsUniTask();

    source.SetResult(42);

    Assert.Equal(42, await task);
    Assert.Equal(42, await task);
}
System.InvalidOperationException : Token version is not matched, can not await twice or get Status after await.

It's also worth noting that the README states "UniTask can not await twice" and doing so is generally unsupported anyway. Still, existing code that caches the result of AsUniTask and awaits it more than once works today and would start throwing, which I think is worth being aware of.

I'm happy to switch to the await version if preferred by the maintainers.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Task.AsUniTask returns a Pending UniTask when the Task is already completed

3 participants