FStreamableHandle (used as part of the FStreamableManager system) has a CancelHandle function that stops it from calling any completion callbacks related to that handle (it could cancel the load request if that is supported by a loader). This works properly if the handle is canceled before it starts to execute the callback. However, if you try to cancel one handle from a completion/cancel callback for another handle that is processed in the same frame, it can call the completion callback after the handle has been canceled because it was already in the execution queue. This is inconsistent because the comment says this will not happen, and it could result in both the completion and cancelation callback happening for the same handle.

Code that can cause this case to occur is attached as StreamableManagerTest.cpp, with this snippet illustrating the problem:

   // Given ...
   TSharedPtr<FStreamableHandle> A, B;
   int Count = 0;
   // ... The ensure() should not fail, but actually it fails:
   A = StreamableManager.RequestAsyncLoad(AssetPath, [this]() {
      ensure(++Count == 1);
   B = StreamableManager.RequestAsyncLoad(AssetPath, [this]() {
      ensure(++Count == 1);
Steps to Reproduce
  1. Copy and paste the contents of StreamableManagerTest.cpp into a file like AsyncLoadingTests.cpp that implements automated engine tests
  2. Compile a product like EngineTest that has automated tests
  3. Execute the System.Engine.StreamableManager test using the session frontend

Expected behavior:

The automated test will succeed

Actual behavior:

The automated test will ensure and fail because it fails to cancel the handle

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-207209 in the post.

Login to Vote

ComponentUE - Foundation - Core
Affects Versions5.05.5
Target Fix5.5
CreatedFeb 16, 2024
UpdatedFeb 19, 2024