Skip to content

Fix cancellation swallowed as AssetRenderException in RenderableAsset render() - #907

Draft
A1shK wants to merge 3 commits into
player-ui:mainfrom
A1shK:repro/cancellation-swallowed-in-render
Draft

Fix cancellation swallowed as AssetRenderException in RenderableAsset render()#907
A1shK wants to merge 3 commits into
player-ui:mainfrom
A1shK:repro/cancellation-swallowed-in-render

Conversation

@A1shK

@A1shK A1shK commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

AI generated summary

render()'s outer catch didn't special-case CancellationException the way doRender()'s inner catch already does. When a parent rehydrates while an in-flight inflateChild() render() call for a child asset is still suspended, the parent's renewHydrationScope() cancellation gets wrapped into AssetRenderException("Failed to render asset") instead of propagating as-is, escaping inflateChild()'s unguarded launch and failing the whole flow.

Includes an isolated repro test demonstrating the race and confirming the fix.

Human explanation

We are seeing a few flakes in our tests with errors saying " failed to render asset" and this is one theory that i want to test out. locally it has reduced some flakes but wanted to test it in a canary to actually confirm that.

Change Type (required)

Indicate the type of change your pull request is:

  • patch
  • minor
  • major
  • N/A

Does your PR have any documentation updates?

  • Updated docs
  • No Update needed
  • Unable to update docs

@A1shK A1shK changed the title Fix cancellation swallowed as AssetRenderException in RenderableAsset… Fix cancellation swallowed as AssetRenderException in RenderableAsset render() Jul 20, 2026
}
}.also { player.cacheAssetView(assetContext, it) }
} catch (exception: Throwable) {
if (exception is CancellationException) throw exception

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copying this

@brocollie08

Copy link
Copy Markdown
Contributor

/canary

brocollie08 and others added 3 commits July 20, 2026 11:31
….render()

render()'s outer catch didn't special-case CancellationException the way
doRender()'s inner catch already does. When a parent rehydrates while an
in-flight inflateChild() render() call for a child asset is still suspended,
the parent's renewHydrationScope() cancellation gets wrapped into
AssetRenderException("Failed to render asset") instead of propagating as-is,
escaping inflateChild()'s unguarded launch and failing the whole flow.

Includes an isolated repro test demonstrating the race and confirming the fix.
RenderableAsset.render()'s rehydrate branch only called
asyncHydrationTrackerPlugin.renderingComplete() from its try/catch
(StaleViewException) bodies, not a finally. If rehydrate(cachedView) throws a
CancellationException instead (e.g. a second rehydrate for the same asset id
cancelling the hydrationScope this one is suspended in), renderingComplete()
is skipped, permanently leaking that asset id in the tracker's pending set.
onHydrationComplete then never fires again for that flow, hanging
IdlingResourcePlugin's waitForIdleSync() until IdlingResourceTimeoutException.

Moved renderingComplete() into a finally block, mirroring doRender()'s
existing correct pattern.

Adds a repro test using an independent sibling asset to isolate the leak
(a later successful render for the SAME asset id would otherwise mask it,
since pending is a plain Set<String> keyed by id).
@A1shK
A1shK force-pushed the repro/cancellation-swallowed-in-render branch from f2d03fd to f1bd06f Compare July 21, 2026 23:00
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.

2 participants