fix: <vimeo-video> element race condition#220
fix: <vimeo-video> element race condition#220spuppo-mux wants to merge 3 commits intomuxinc:mainfrom
<vimeo-video> element race condition#220Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
@spuppo-mux is attempting to deploy a commit to the Mux Team on Vercel. A member of the Team first needs to authorize it. |
|
Closes #219 |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| this.#hasLoaded = null; | ||
| this.#isInit = null; | ||
| super.disconnectedCallback?.() | ||
| } |
There was a problem hiding this comment.
Stale loadComplete after disconnect causes premature resolution
High Severity
disconnectedCallback resets #hasLoaded to null but doesn't reset loadComplete. After reconnect, load() checks if (this.#hasLoaded) which is null (falsy), so it skips creating a new PublicPromise. The old already-resolved loadComplete is reused, causing await this.loadComplete at line 213 to resolve immediately — before the video actually loads. This also affects play(), pause(), and other methods that await this.loadComplete. Adding this.loadComplete = new PublicPromise() to disconnectedCallback would fix this.
Additional Locations (1)
| this.#loadRequested = null; | ||
|
|
||
| if (this.#hasLoaded) this.loadComplete = new PublicPromise(); | ||
| this.#hasLoaded = true; // TODO: Identify how hasLoaded differs from isInit |
There was a problem hiding this comment.
Reordered loadComplete refresh enables null api dereference
Medium Severity
Moving if (this.#hasLoaded) this.loadComplete = new PublicPromise() from before the 1-tick await to after it introduces a timing regression on second+ loads. When src and loop change in the same synchronous block (common in React/Next.js), the loop handler's await this.loadComplete resolves immediately on the stale promise. Its continuation then runs after load() sets this.api = null, causing this.api.setLoop(...) to throw a TypeError. Previously, loadComplete was refreshed before the await, so the loop handler would correctly suspend until the new load completed.


By checking logs I saw that when the bug happened, we were getting into the
isInit === falsecase (and load was running just one time), so the options weren't being applied.Tested this mainly on nextjs example. Could originally reproduce semi-consistently by switching to TikTok player and then back to vimeo. When the bug happens we see the Vimeo default color (blueish)


When the config applies correctly we should see a pinkish color
To address the race condition:
await (this.#loadRequested = Promise.resolve());to the top of the functiondisconnectedCallbackto clear state on unmount.Extra:
#setupApiListenersfunction#onLoadedlistener to a new method since it's now used from two functionsloadfunction so it's clearer to read.isInitandhasLoadedare pretty similar semantically, was wondering if one of them can be removed.optionsto new VimeoPlayerAPI call (did not seem to have effect even though it's specified in the JSdocs)Note
Medium Risk
Changes the
load()lifecycle and player initialization timing for the custom element, which can affect autoplay/controls/config application and event ordering. Risk is moderate because it targets an initialization race but touches core state/reset and promise resolution paths.Overview
Fixes a race in
<vimeo-video>initialization by moving the one-tick#loadRequestedgating earlier and resettingloadComplete/#hasLoadedafter that tick, ensuring options/config are applied consistently on first init vs subsequentloadVideo()calls.Refactors load completion and listener wiring by extracting shared logic into
#onLoaded()and#setupApiListeners(), passesoptionsintonew VimeoPlayerAPI(iframe, options), and addsdisconnectedCallback()to clear internal init/load flags on unmount to avoid stale state across remounts.Written by Cursor Bugbot for commit 50ef896. This will update automatically on new commits. Configure here.