Exact pin on a shared singleton let one team's deploy crash another team's unchanged remote
Module Federation resolved a shared Angular Material singleton to a newer version and crashed an unchanged remote in testing, a dev.to post reports. Every per-repo check had passed. The fix was one character, a caret added to an exact version pin.
The Engineer · Build desk

Inventory offered 19.2.3, the highest, so it won. Orders pinned exactly 19.2.1, so 19.2.3 failed its check. No step in either pipeline looked at the remotes combined. mfe-guard fails when a participant will not accept the winner. The fix: '^19.2.1'.
- exposure Inventory remote Offered 19.2.3, the version it was built with; the highest version wins under the default strategy, claim 6
- constraint Orders remote Pinned the exact version 19.2.1, so the winning 19.2.3 failed its check, claim 8
- constraint Both teams' CI pipelines No step in either pipeline ever looked at the two remotes combined at runtime, claim 12
- capability mfe-guard CLI Works out which singleton version will win and fails when any participant will not accept it, claim 17
- decision The one-character fix Changing '19.2.1' to '^19.2.1', then rebuilding and redeploying orders, claim 13
| Who | How | Kind | Claim |
|---|---|---|---|
| Inventory remote | Offered 19.2.3, the version it was built with; the highest version wins under the default strategy | exposure | 6 |
| Orders remote | Pinned the exact version 19.2.1, so the winning 19.2.3 failed its check | constraint | 8 |
| Both teams' CI pipelines | No step in either pipeline ever looked at the two remotes combined at runtime | constraint | 12 |
| mfe-guard CLI | Works out which singleton version will win and fails when any participant will not accept it | capability | 17 |
| The one-character fix | Changing '19.2.1' to '^19.2.1', then rebuilding and redeploying orders | decision | 13 |
What happened
- The console showed a minified ReferenceError in a component that had not changed, and the underlying Federation Runtime version error took the better part of a day to find.
- With strictVersion the runtime throws; without it, the pinned remote silently runs on a version it was never built or tested against.
- The post's CLI, mfe-guard, reads each remote's deployed mf-manifest.json, computes the winning singleton version, and exits with code 1 on any error.
Why it matters
- constraint The guard runs after a deploy to the test environment, so it sees only the remote versions deployed there. A combination that first meets in production gets no check.
- decision Teams with exact pins on shared singletons have a list to review. The tool treats each one as a crash waiting for the next patch release from a neighbouring team.
- exposure A passing check still leaves compatible drift untested. The post's example is a remote built on ui-kit 2.13 that will run on 2.17, reported at info level only.
- cost Adoption is one config file of manifest URLs and one CI step. The cost it targets is the debugging day the author's team lost, which the author calls the expensive part.
Nothing in the failing remote's repo had changed [1]. The trigger was a different team's remote built on an Angular Material two patch numbers ahead of the version the failing remote had pinned [24]. Of the example, the post's author wrote: "Names and versions changed. The shape of the bug is real." [4]
The highest-wins rule is what turns a patch release into a cross-team event. Under the default strategy the highest offered version becomes the winner [6], and each participant then checks that winner against its own requiredVersion [7]. An exact pin on a lower version cannot pass that check [8]. Any remote pinned exactly below the winner breaks the moment a neighbour ships a higher one [6][8].
In this case the pin was the defect. The CLI the post describes warns on singletons pinned to an exact version and calls them "a crash waiting for the next patch release" [19]. It raises an error on different major versions of a shared package [18]. We think the workable rule from this account is to align on the major and declare a range inside it.
The strictVersion flag decides how loud the failure is. With it, the runtime throws the version error. Without it, the pinned remote silently runs on a version it was never built or tested against [9]. If that happens halfway through loading a module graph, the errors point nowhere near the cause [10]. The team's first signal was a minified ReferenceError [1]. The version error took most of a day to find [3].
CI had no way to see it. Orders built on its pinned version, inventory built on the newer one, and unit, lint and e2e tests passed in each app [11]. Each pipeline was right about the one repo it could see, and no step in either looked at the combination [12].
The data to predict the crash already exists on deployed remotes. Builds on @module-federation/enhanced, which Nx, rspack, Rsbuild and Modern.js use, write an mf-manifest.json beside each remoteEntry.js [15]. It lists the version each remote ships, the requiredVersion it accepts and whether the package is a singleton [15]. The checker needs only the deployed manifest URLs, not access to other teams' source [16]. For participants without manifests, a project mode reads package.json and node_modules [23].
Transfer depends on the test environment. The guard reads whatever is deployed at the URLs it is given [17], so a pass is only as good as the match between that environment and the remote versions production will hold. This is also one account of one incident. The author says the first run against a real test environment flagged minor drift nobody had noticed [25].
What to watch
- Whether mfe-guard's drift reports turn out to predict real failures once it runs against environments that mirror production's remote versions.
- Whether setups that do not emit mf-manifest.json get the same coverage from project mode, which reads package.json and node_modules instead of deployed artifacts.
Clarity's read
What the record supports and how the coverage leans. The claims behind it follow.
Reality
- Evidence55
- Adoption
- Insufficient
- Hype gap+5
- Incentives35
- Confidence60
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
A remote that had not changed started crashing in the test environment with 'ReferenceError: Cannot access '_t' before initialization', and the component in the stack trace had not changed either.
- [2]
Every CI pipeline was green and every build passed; the app only broke when the shell loaded the remote next to a brand-new remote from another team.
- [3]
It took the better part of a day to find the real error underneath: a Federation Runtime error saying version 19.2.3 from inventory of shared singleton module @angular/material/autocomplete does not satisfy the requirement of orders, which needs 19.2.1.
- [4]
The author wrote: 'Names and versions changed. The shape of the bug is real.'
- [5]
The platform is an Angular micro-frontend setup on Module Federation: a shell loads several remotes, each built and deployed from its own repo by its own team, with Angular, RxJS and the UI kit shared as singletons so that only one copy is loaded.
- [6]
Under the default strategy, every loaded participant offers the version it was built with and the highest version wins; here that was 19.2.3, from inventory.
- [7]
Every participant checks the winning version against its own requiredVersion.
- [8]
The orders remote pinned the exact version 19.2.1, so the winning 19.2.3 failed its check.
- [9]
With strictVersion the runtime throws the version error; without it, orders silently runs on a version it was never built or tested against.
- [10]
When a version mismatch happens halfway through loading a module graph, you get errors like 'Cannot access '_t' before initialization', which point nowhere near the real cause.
- [11]
Every check looked at one repo at a time: orders built fine with 19.2.1, inventory built fine with 19.2.3, and unit tests, lint and e2e tests all passed per app.
- [12]
The conflict only exists when the two remotes are combined at runtime in the browser, and no step in either pipeline ever looked at that combination.
- [13]
The fix took one character: changing '@angular/material': '19.2.1' to '^19.2.1', then rebuilding and redeploying orders.
- [14]
The author says the day lost to debugging was the expensive part, and that a bug that only shows up when two teams' deploys meet will come back in some other form.
- [15]
@module-federation/enhanced, used by Nx, rspack, Rsbuild and Modern.js, writes an mf-manifest.json next to every remoteEntry.js listing every shared package with the version that remote ships, the requiredVersion it will accept, and whether it is a singleton.
- [16]
Predicting the crash needs no source access to other teams' repos, only the URLs of their deployed manifests.
- [17]
mfe-guard is a small CLI that fetches the manifests of the shell and remotes, works out which version of each singleton will actually win at runtime, and fails when any participant will not accept it.
- [18]
mfe-guard reports as errors a singleton whose winning version does not satisfy someone's requiredVersion, different major versions of a shared package, and two remotes using the same federation name.
- [19]
mfe-guard warns on singletons pinned to an exact version, described as 'a crash waiting for the next patch release', and on @angular/core, rxjs, zone.js or React shared without singleton: true.
- [20]
mfe-guard reports compatible drift at info level, for example 'orders was built on ui-kit 2.13 but will run on 2.17 at runtime'; it is not an error, but you probably want to test it.
- [21]
Setup is a config file in the shell repo listing each participant's name and manifest URL, plus one CI step, 'npx mfe-guard check', after a remote deploys to the test environment.
- [22]
The command exits with code 1 on any error, so the pipeline stops before the combination reaches production.
- [23]
A project mode (-p name=./path) reads package.json and node_modules when you do not have manifests.
- [24]
The conflicting versions, 19.2.3 and 19.2.1, differ by two in the patch number.
- [25]
The author says the first time they ran mfe-guard against their real test environment, it flagged minor drift that nobody had noticed.
Get this ledger inside ChatGPT. Ask about any of our stories and the answer brings its figure, each claim’s verdict and the sources. Free, no account.
Sources
1 independent publisher whose own reporting we read for this story.
- dev.toThe Module Federation bug that passed every build and crashed in the browser
1 article · October 14, 2026
Topics and entities
Follow any of these and your For You feed starts watching them — no settings page required.
Topics
- Dependency ManagementFollow
- Micro-frontendsFollow
- CI/CD pipelinesFollow
- Module federationFollow