Skip to content

fix(core): ignore stale async prop loads before post-processing - #10846

Open
Muhtasim-Munif-Fahim wants to merge 1 commit into
visgl:masterfrom
Muhtasim-Munif-Fahim:fix/stale-async-prop-release
Open

Muhtasim-Munif-Fahim wants to merge 1 commit into
visgl:masterfrom
Muhtasim-Munif-Fahim:fix/stale-async-prop-release

Conversation

@Muhtasim-Munif-Fahim

@Muhtasim-Munif-Fahim Muhtasim-Munif-Fahim commented Oct 11, 2026 •

Copy link
Copy Markdown

Closes #10827

Background

A stale async completion ran _postProcessValue before _setAsyncPropValue discarded it, so the prop type's release hook destroyed the current value (e.g. the active iconAtlas texture). Stale results are now dropped first. Unlike the guard in the issue (loadCount !== pendingLoadCount), this only skips loads older than the last resolved one, so an older load that resolves while a newer one is still pending is accepted as before.

Change List

  • ComponentState._watchPromise: return early if a newer load already resolved
  • Unit tests

Tests: vitest --project headless test/modules/core test/modules/layers → 701 passed; the new test fails without the fix. Biome clean.

AI assistance was used to help find the cause, write the patch, and run tests; I reviewed the change.


Note

Medium Risk
Touches core async prop lifecycle and resource release timing; fix is localized but affects all components using async props with release/transform.

Overview
Fixes a race where an out-of-order async prop resolution still ran _postProcessValue (including release on the live resolved value) even though _setAsyncPropValue would later ignore that load. Stale completions are now dropped before post-processing when loadCount is older than resolvedLoadCount, so in-use resources (e.g. textures) are not torn down by a late promise.

The guard is narrower than “load still pending”: an older load that finishes while a newer one is still in flight can still apply, matching existing behavior. A unit test covers newer-then-older resolution and asserts the current value is unchanged and release/transform are not run for the stale result.

Reviewed by Cursor Bugbot for commit 7afe5bb. Bugbot is set up for automated code reviews on this repo. Configure here.

When an async prop changes while an earlier load is pending and the loads
resolve out of order, the stale completion ran _postProcessValue before
_setAsyncPropValue discarded it. That called the prop type's release hook
on the current value, e.g. destroying the active IconLayer iconAtlas
texture.

Return early when a more recent load has already resolved.

Fixes visgl#10827
@greptile-apps

greptile-apps Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Medium impact] Fixes stale async property resolution in component lifecycle.

The PR appears safe to merge, with a non-blocking request to test the opposite completion order.

Findings

  1. P2 Older-first behavior lacks coverage ▶

Summary

The PR drops stale promise results before _postProcessValue can release the current resource.

  • Async props skip older results before processing them.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Promise completes] --> B{Component still active?}
  B -->|No| C[Ignore result]
  B -->|Yes| D{Newer load already resolved?}
  D -->|Yes| C
  D -->|No| E[Release old value and transform result]
  E --> F[Store result and notify listeners]
Loading

Reviews (1) · Last reviewed commit: "fix(core): ignore stale async prop loads..." · Reviewed by Greptile

Comment on lines +227 to +228
// The newer load resolves first
newerLoad.resolve('newer');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Older-first behavior lacks coverage

The new test only covers the newer load finishing first. It would also pass with loadCount < asyncProp.pendingLoadCount, which would wrongly discard an older result while the newer load is still pending.

Add an older-first case that checks the older value is transformed and shown, loading stays true, and the newer result later replaces it. This protects the behavior the PR explicitly preserves.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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.

[Bug] Stale async iconAtlas completion destroys the currently active texture (v9.4.0)

1 participant