fix(BEE-11886): strict mode race condition#16
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes a StrictMode-induced "Bee is not started" error by moving SDK construction out of render and adding guards against stale async resolutions across mount/unmount cycles.
Changes:
- Move
new BeefreeSDK(...)andstart()/join()from render-time into auseEffect, with adisposedclosure flag that suppresses stale.then()/.catch()callbacks from a prior mount. - Add
startedRefdecoupled fromeditorReady, so theloadConfigeffect only fires when an instance was actually observed to start (not just when the flag flipped). - Wrap
loadConfig()intry/catchbecauseexecuteActionthrows synchronously, so a chained.catch()alone wouldn't capture the error.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
simone-ferrario
approved these changes
Jun 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes an intermittent
Error: Bee is not startedthrown from a passiveeffect when
<Builder>mounts under<React.StrictMode>— the default inNext.js (
reactStrictMode: true) and Create React App. Without this fix,the wrapper is effectively unusable out-of-the-box in modern React apps
unless StrictMode is disabled app-wide.
Root cause
Builder.tsxconstructs the SDK during render and flipseditorReadyfrom an unawaited
.then():Under StrictMode's mount → cleanup → re-mount cycle:
calling start() again (still unresolved).
calling loadConfig(callbacks) on Bee B, whose underlying SDK instance
isn't started → executeAction throws "Bee is not started".
Two amplifiers make it fatal:
loadConfig().catch(...) never attaches — the error escapes the effect
and hits the nearest error boundary.
The fix
src/Builder.tsx — three discrete changes, no reordering:
disposed flag captured in closure. The .then() and .catch()
handlers if (disposed) return so a stale resolution from a prior
mount cannot mutate state for a different mount cycle. The cleanup
from the old standalone useEffect(() => { ... }, [container])
folds into this effect's cleanup.
the .then() after the disposed check. The loadConfig effect then
gates on startedRef.current — distinguishing "flag flipped" from
"this instance actually observed to start." A stale resolution can't
trick the gate.
synchronously, so a chained .catch() is insufficient.
Total diff: +60 / -41 in src/Builder.tsx. Nothing else touched.
Behavior changes
The construct effect uses [token, container] deps. v1.0.3's render-time
guard (instanceRef.current === null && token) silently ignored
token-prop changes after first construct. With this fix, a new token
prop tears down the old instance and constructs a new one. This is
arguably the more correct React-idiomatic behavior; consumers who refresh
tokens should already prefer useBuilder().updateToken() and won't see a
difference. Flag if this is a concern.
Test plan
expectations
under <React.StrictMode> for 5+ cycles never triggers the error
boundary; trace logs show the disposed flag suppressing stale
resolutions on every StrictMode re-mount
Repro harness (not in this PR): a clone of this repo at v1.0.3 with
<React.StrictMode> added in example/index.tsx and a Home/Builder
toggle + bounce-stress button in example/App.tsx. Reliably reproduces
the bug against the unpatched Builder.tsx and reliably does NOT
reproduce against this patch.
Out of scope (potential follow-up)
so the wrapper doesn't have to reach into DOM (innerHTML = '') to
tear an instance down. Worth its own ticket against the SDK package.
Type of Change
Related Issues
https://growens.atlassian.net/browse/BEE-11886
Fixes #
How Has This Been Tested?
Checklist
[Unreleased]