Search Unity

  1. Looking for a job or to hire someone for a project? Check out the re-opened job forums.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

await Addressables.LoadAssetAsync Exceptions not bubbling (1.1.7)

Discussion in 'Addressables' started by CharBodman, Aug 7, 2019.

  1. CharBodman

    CharBodman

    Joined:
    Sep 20, 2018
    Posts:
    36
    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.

    Code (CSharp):
    1.  
    2. try
    3. {
    4.     var someAsset = await Addressables.LoadAssetAsync<ISomeAsset>("A key not found").Task;
    5. }
    6. catch
    7. {
    8.     Debug.Log("I wont get here");
    9. }
    10.  
    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

    Code (CSharp):
    1. public async Start() {
    2.     AsyncOperationHandle<Texture2D> handle = Addressables.LoadAssetAsync<Texture2D>("mytexture");
    3.     await handle.Task;
    4.     // The task is complete. Be sure to check the Status is succeessful before storing the Result.
    5. }
    This wont work if an exception is thrown as the task will never complete.
     
    Last edited: Aug 7, 2019
  2. CharBodman

    CharBodman

    Joined:
    Sep 20, 2018
    Posts:
    36
    This is my solution to the problem.


    Code (CSharp):
    1.  
    2. public class AddressablesUtil
    3. {
    4.     public static Task<T> LoadAssetAsync<T>(object key)
    5.     {
    6.         TaskCompletionSource<T> taskCompletionSource = new TaskCompletionSource<T>();
    7.  
    8.         AsyncOperationHandle<T> loadAssetHandle = Addressables.LoadAssetAsync<T>(key);
    9.  
    10.         loadAssetHandle.Completed += (AsyncOperationHandle<T> completedHandle) =>
    11.         {
    12.             if (completedHandle.OperationException != null)
    13.             {
    14.                 taskCompletionSource.SetException(completedHandle.OperationException);
    15.             }
    16.             else
    17.             {
    18.                 taskCompletionSource.SetResult(completedHandle.Result);
    19.             }
    20.         };
    21.  
    22.         return taskCompletionSource.Task;
    23.     }
    24. }
    25.  
    Usage
    Code (CSharp):
    1.  
    2.  
    3. try
    4. {
    5.     var loadedAsset = await AddressablesUtil.LoadAssetAsync<AssetType>("key not found");
    6. }
    7. catch(Exception e)
    8. {
    9.     // yay this works now.
    10.     Debug.LogException(e)
    11. }
    12.  
     
    Last edited: Aug 7, 2019
    ThomRobinGames and kaimelis like this.
  3. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    1,051
    This sounds like a bug, and we should be bubbling those up.
     
    Cfirzi, kaimelis and CharBodman like this.
  4. c_Feng

    c_Feng

    Joined:
    May 15, 2017
    Posts:
    19
    It seems like I'm still running into this issue. I'm on Unity 2019.2.21f using Addressables 1.8.3.
     
    mike6502 and pahe like this.
  5. CameronND

    CameronND

    Joined:
    Oct 2, 2018
    Posts:
    49
    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
     
  6. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    1,051
    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.
     
  7. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    477
    @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.
     
unityunity