In production, what concrete symptoms show up when a library that was supposed to be a singleton across microfrontends ends up loaded twice on the same page, and how would you diagnose that it's a duplicate-instance problem rather than an application bug?
answer
- invalid hook call = two React copies
- bug confined to one remote's boundary
- load-order dependent bugs
- check Network tab for duplicate chunk
- shared-scope registry inspection
basics
~20 sYou'll see weird bugs like broken shared state, theme/context not applying somewhere, or a hooks crash -- but only for one part of the page, not everywhere. Checking the browser's network tab shows the same library file downloaded twice, which confirms two separate copies are running.
solid answer
~50 sDuplicate instances of a supposedly-singleton library manifest as state that doesn't propagate across a boundary that looks like it should be one component tree: React context providers whose consumers read default values, Redux/Zustand stores that silently diverge into two separate copies with different data, router history desyncing from the address bar, or hard crashes like 'invalid hook call' when a hook from one React copy runs against a different copy's dispatcher. The tell is that it's scoped -- broken only inside one microfrontend's boundary, not globally -- and that the bug appears or disappears based on load order or which remote loaded first. To diagnose, inspect the network tab for two separate chunk downloads of the same library, check the federation runtime's shared-scope registry at runtime, or log the library's internal identity from each microfrontend to see if they differ.
go deeper
Should recognize that seeing the same library downloaded twice in the Network tab is a red flag, even without deep knowledge of why it breaks things.
Should connect specific symptoms (broken context, invalid hook call, desynced state) to the underlying cause of two separate module instances.
Should describe the load-order-dependent, boundary-scoped signature that distinguishes this from an ordinary bug, and know concrete diagnostic techniques (network inspection, shared-scope registry, identity comparison).
Should discuss how to prevent this class of bug systemically -- CI checks that fail a build on unsatisfiable shared-dependency ranges, strictVersion policies, or dashboards that alert on duplicate chunk loads in production data -- rather than only diagnosing it after the fact.
## Why two copies misbehave When a shared dependency was intended to be a singleton but two separate copies end up loaded on the same page, the resulting bugs have a distinctive shape because JavaScript module identity is per-bundle: two independently compiled copies of the same library, even at the exact same version, are two different sets of objects, functions, and closures in memory. Anything that library uses to hold shared, page-wide state exists twice, and the two copies have no way to see each other, because nothing in the language links them; they're just two unrelated objects that happen to have identical code: - a module-level variable - a React Context's underlying object - a Redux store instance - a router's history object ## The symptoms 1. **A React-specific class of crash** is the most common and recognizable symptom: 'Invalid hook call. Hooks can only be called inside the body of a function component,' or a subtler variant where the app doesn't crash but a `useContext` call silently returns the Context's default value instead of the value a provider higher up the tree set. This happens because React's hooks dispatcher is stored as module-level state inside the React package itself; if the component calling the hook was bundled against a different copy of `react` than the one that's actually rendering the tree (the one whose reconciler is currently 'active'), the hook call reaches into the wrong dispatcher and either finds nothing valid (crash) or finds a Context object that no provider from the other React instance ever touched (silent default value). 2. **A second common symptom is state divergence**: two copies of a Redux or Zustand store exist, one microfrontend dispatches an action, and a sibling microfrontend reading from 'the same' store never sees the update, because it's reading its own private, un-updated copy. 3. **A third is routing desync**: two router history instances exist, one updates the browser's address bar, and a component relying on the other instance's history renders as if navigation never happened, or vice versa -- clicking a link changes the URL but the visible UI doesn't update. ## The diagnostic signature The defining diagnostic signature that distinguishes this from an ordinary application bug is scope and load-order sensitivity. - **An ordinary bug.** A normal logic bug is usually reproducible consistently and isn't tied to which microfrontend loaded first or which route was visited first in the session. - **A duplicate-instance bug**, by contrast, is often confined to exactly one microfrontend's boundary (state doesn't propagate past microfrontend B's root, but works fine inside B alone and inside A alone), and it can appear or disappear depending on load order -- if microfrontend A happens to load first and 'wins' the shared-scope registration, B might get silently downgraded to its own bundled copy and break, but if a user's session happens to trigger B's route first, the roles reverse and A breaks instead. This nondeterminism, tied to navigation order rather than to input data, is the strongest tell. ## Confirming the diagnosis To confirm the diagnosis in practice: 1. **The fastest check is the browser Network tab**: filter for the suspect library's chunk and look for it being requested and downloaded more than once across the microfrontends on the page -- a singleton dependency, correctly deduplicated, should show exactly one network request for its chunk regardless of how many microfrontends declare it. 2. **Module Federation runtimes also expose their shared-scope registry** at runtime, which can be inspected in the console to see how many distinct module instances were actually registered for a given package name versus how many were requested. 3. **A more surgical technique** is to have each microfrontend log something derived from the library's module identity -- a unique Symbol defined at module scope, or simply comparing an internal export both are expected to share for strict equality -- since two different bundled copies will fail an identity comparison even if their version strings print identically. ## A real-world instance A well-known real-world instance of this failure class is teams migrating a Module Federation setup from a strict single-React-version constraint to allowing multiple remotes on slightly different React minor versions: even 'compatible' semver ranges can end up as two separate instances if the negotiation falls back due to a range that technically doesn't overlap, and the resulting bug reports ('the dropdown menu inside the embedded widget doesn't close on outside click,' 'the theme provider isn't applying inside the payments widget') are exactly this signature -- functionality that depends on shared context or global listeners breaking only inside the boundary of whichever remote ended up with the orphaned second copy.
- Why does a duplicate React instance cause 'Invalid hook call' specifically, rather than some more generic error?React's hooks rely on a dispatcher object stored as module-level state inside the react package; a component compiled against one copy of react calls into that copy's dispatcher, and if the actual rendering is being driven by a different copy's reconciler, the dispatcher lookup finds either nothing valid or a mismatched context, which React's internal invariant checks report as an invalid hook call.
- Why is load order relevant to whether this bug appears at all?In federation's negotiation, whichever remote's version gets registered into the shared scope first becomes the instance others are checked against; if a later remote's declared range doesn't satisfy that first instance, it falls back to its own copy. Since which remote loads first can depend on which route or widget the user visits first, the same deployed code can pass or fail depending on session navigation order.
- Besides the Network tab, what's a reliable in-code way to confirm two microfrontends are running different instances of the same library?Compare an internal reference both are expected to share -- for example a module-scoped Symbol, a singleton class instance, or a store reference -- with strict equality across the two microfrontends; if it's the same instance, the comparison is true, and if two separate bundled copies exist, it will be false even though both report the same version string.
It's like two branches of a company each keeping their own separate copy of the master customer ledger instead of sharing one. Both ledgers look identical in format, but updates made in one never show up in the other -- so a customer who calls branch A after being helped by branch B gets told 'we have no record of you,' even though 'the same system' supposedly serves both.
saying these in an interview costs you the question
- Treats every context/hooks bug as a generic application logic bug
- Doesn't connect 'invalid hook call' to duplicate library instances
- Assumes the bug would be 100% reproducible regardless of load order
- Has no concrete way to verify duplication beyond guessing
- Doesn't know duplicate instances can occur even when both remotes report the 'same' version