Fix live toast stale callback race#271
Conversation
7ea74cf to
cff04ae
Compare
cff04ae to
31a5a56
Compare
|
I am not able to repro this bug, can you share a minimal repo for us to test and repro it. |
|
Sure. I added a minimal dependency-free repro repo here: https://github.com/jjoanna2-debug/impeccable-toast-race-repro Steps: Then open What it does:
The same page has Run fixed implementation, which uses the I kept it static and framework-free so the repro isolates the toast lifecycle race itself rather than depending on a particular React/Vite page shape. |
|
Quick status refresh: this is still current and green. I re-ran the focused regression guard locally on Node v26.4.0: node --test tests/live-browser-regression.test.mjsResult: 28 pass, 0 fail. The minimal repro is still here: It isolates the failing sequence: Current PR checks are green, including |
|
Seems sensible - thank you for your contribution! |
New upstream features: - Bump AI SDK packages to v7 (pbakaus#336) - Fix live toast stale callback race (pbakaus#271) - Replace Alumni Sans Pinstripe with Alumni Sans across the type system - Bump bun minor/patch deps + actions/cache from 5 to 6 Security findings: wildcard postMessage in browser extension (by-design), mutable GH Actions tags (upstream), dependabot missing cooldown (fixed) Security fixes: added cooldown: default-days: 7 to dependabot.yml (bun + github-actions ecosystems) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
dismissToast()or a newer toast from leaving stale callbacks that touchtoastElWhy
Fixes #268.
showToast()schedules an enterrequestAnimationFrame, butdismissToast()can remove the current toast and settoastEl = nullbefore that frame runs. The old callback then readtoastEl.styleand could throw. A plain null guard would close that crash, but it still leaves older timeout callbacks able to animate or remove a newer toast.This patch captures the created element as
currentToastand makes each delayed callback no-op unlesstoastEl === currentToast.Verification
node --test tests/live-browser-regression.test.mjsnode --test tests/live-browser-regression.test.mjs tests/live-browser-source.test.mjs tests/live-browser-dom.test.mjs tests/live-browser-script-parts.test.mjs tests/live-browser-session.test.mjsgit diff --checknpx --yes bun run test:livestill fails ontests/live-copy-edit-agent.test.mjs(flags invalid JSX syntax in post-apply checks); confirmed the same failure on cleanorigin/main.npx --yes bun run test:live-e2eis blocked in this checkout because@anthropic-ai/sdkis not installed.Note
Low Risk
Scoped UI toast lifecycle fix with regression tests; no auth, data, or API surface changes.
Overview
Fixes a timing race in live-mode
showToast()where enterrequestAnimationFrameand auto-dismisssetTimeoutcallbacks could run afterdismissToast()or a newer toast replaced the globaltoastEl, causing crashes or animating/removing the wrong toast.Each toast now binds delayed work to a local
currentToast; enter, fade-out, and removal callbacks no-op unlesstoastEl === currentToast. Regression tests inlive-browser-regression.test.mjslock in that ownership behavior.Reviewed by Cursor Bugbot for commit 31a5a56. Bugbot is set up for automated code reviews on this repo. Configure here.