I noticed when awaiting the Addressables.LoadAssetAsync task, exceptions are not being set to the operation task.
This will cause the game/task to forever await.
try
{
var someAsset = await Addressables.LoadAssetAsync<ISomeAsset>("A key not found").Task;
}
catch
{
Debug.Log("I wont get here");
}
Anyone else notice this or use async await with loading assets? Maybe it’s not designed to be used this way?
The documentation tells you to use it is the following
public async Start() {
AsyncOperationHandle<Texture2D> handle = Addressables.LoadAssetAsync<Texture2D>("mytexture");
await handle.Task;
// The task is complete. Be sure to check the Status is succeessful before storing the Result.
}
This wont work if an exception is thrown as the task will never complete.
This is my solution to the problem.
public class AddressablesUtil
{
public static Task<T> LoadAssetAsync<T>(object key)
{
TaskCompletionSource<T> taskCompletionSource = new TaskCompletionSource<T>();
AsyncOperationHandle<T> loadAssetHandle = Addressables.LoadAssetAsync<T>(key);
loadAssetHandle.Completed += (AsyncOperationHandle<T> completedHandle) =>
{
if (completedHandle.OperationException != null)
{
taskCompletionSource.SetException(completedHandle.OperationException);
}
else
{
taskCompletionSource.SetResult(completedHandle.Result);
}
};
return taskCompletionSource.Task;
}
}
Usage
try
{
var loadedAsset = await AddressablesUtil.LoadAssetAsync<AssetType>("key not found");
}
catch(Exception e)
{
// yay this works now.
Debug.LogException(e)
}
3 Likes
This sounds like a bug, and we should be bubbling those up.
3 Likes
It seems like I’m still running into this issue. I’m on Unity 2019.2.21f using Addressables 1.8.3.
2 Likes
I came across this previously too and when trying to debug it I found that in my case what was happening was a custom method was being used in a chained operation and if it raised an exception it wouldn’t get propagated up to the topmost operation properly.
In 1.7.5 using 2019.2.9f
sorry to be so slow in getting back to this, but I as mistaken in my first response. The exception isn’t bubbled up because we never bubble up exceptions. Whether you are using the callback, yield return, or await, we do two things with exceptions. One is we feed them into the ResourceManager.ExceptionHandler. By default this just logs as an error, but you can override that to do whatever you want. Second is we return it with the operationHandle.OperationException
The reason we did this is that the code actually creating the exceptions has no idea if you are using a Task or callback or other. Task is the only context where it might make sense to actually throw. So we aimed for consistency. I’m making a note to be more clear in our docs about this.
@unity_bill
The confusing thing about the OperationException is that it doesn’t contain any useful information for runtime handling. I see 4 error logs when an error happens (1 of those being the OperationException, so it might be double logged), but when I look at the OperationException, it doesn’t contain the information about the other 2/3 internal errors. I would expect them to at least be nested under the Exception’s innerException
. Because of this lack of information, I’m forced the leave exception logging on, even if there are cases that are able to be handled gracefully.