Troubleshooting
Start with the built-in diagnostics, run from the project root:
mfe-forge doctor # human-readable; exit code 2 when a check fails
mfe-forge doctor --json # { ok, summary: { pass, warn, fail }, checks: [{ id, status, message, hint }] }
mfe-forge check # manifest and port validation
mfe-forge status # what the CLI discoveredInclude the doctor --json output when you report a bug.
Doctor checks
| Check id | Failure message | Fix |
|---|---|---|
node-version | Node vX is too old | Install Node.js 20 or newer. |
lockfile | No lock file found for <pm> | Run <pm> install. The expected file is bun.lock/bun.lockb, pnpm-lock.yaml or package-lock.json depending on defaults.packageManager. If you switched package managers, update the config with mfe-forge config --set defaults.packageManager --value <pm>. |
ports | Port conflicts: a and b both use port N | Change port in one vite.config.ts (both server and preview) and the --port in that app's dev and preview scripts. |
hosts | Scopes without a host: x | mfe-forge generate host x/host. Only reported when the project has at least one app. |
workspaces | Root package.json missing workspaces configuration | Add "workspaces": ["apps/*/*", "packages/*"]. The check only verifies the field exists, not that it matches your apps. |
Commands run from the wrong directory
Symptom: No apps found to run, App "x" not found, doctor reports No root package.json found, or config --show prints a name that is your current folder name.
The CLI uses the current working directory as the project root and does not search parent directories for apps/. cd to the folder that contains mfeforge.config.js and apps/.
Configuration errors
Invalid MFE Forge configuration: followed by path: message lines, exit code 3. The config parsed but failed the schema. Common cases: defaults.packageManager not one of bun, pnpm, npm; dev.portRange not a two-number array; an unknown enum value in testing, ci or federation.plugin. Run mfe-forge config --validate to list the issues.
Warning: Failed to load .../mfeforge.config.ts: ... Falling back to default configuration. The .ts loader does not compile TypeScript. It strips imports, comments, simple type annotations and as/satisfies, then evaluates the default export. It fails on:
No default export found in configuration file;- references to imported values (the imports are removed, so the identifiers are undefined);
- a default export that is not an object:
Default export must evaluate to a configuration object; - TypeScript syntax beyond the simple cases (interfaces, enums, complex generics).
Keep the default export a self-contained object literal. When this warning appears, every command runs with default settings, including the bun package manager.
Generation errors
| Message | Cause | Fix |
|---|---|---|
Invalid type "x". Valid: app, host, package, design-system, library, pkg | Unknown generator | Use one of the listed types. pkg is an alias of package. |
Apps and hosts must be scoped: "x" → try "x-scope/x" | Missing scope | Use scope/name, for example shop/catalog. |
Directory already exists: <path> | Target exists | Pick another name or remove the directory. init prints Directory <name> already exists. |
Host "x/host" not found. Run "mfe-forge generate host x/host" to create it. | Remote generated before its host (warning only) | Generate the host; it picks up existing remotes of its scope. Or pass --host <scope/host> / --skip-host. |
No available ports found in the configured range | Every port in dev.portRange is used or bound | Widen dev.portRange or pass --port. |
Template error: ... | Template rendering failed | The partial directory is removed. Report it as a bug. |
Names entered at the interactive prompt must match ^[a-z][a-z0-9-/]*$. An @org/ prefix on the name is stripped.
Host does not pick up a remote
Warning: "remotes: {" section not found in .../vite.config.ts (from generate) or Warning: Could not find "remotes: {" section in ... (from sync). The CLI locates the host's remotes with a regular expression on the literal text remotes: {. If you moved remotes into a variable, a spread or a helper function, the CLI cannot update them; keep an inline remotes: { ... } object in the federation call.
Other causes:
- The remote is in another scope. A host only receives remotes from its own
apps/<scope>/. - The remote directory has no
vite.config.ts, so discovery ignores it. - The block contains hand-written entries:
syncreplaces the entire block, so they are removed. Keep manual remotes outside the CLI-managed block or re-add them after syncing.
mfe-forge sync --dry-run --diff shows which files would change without writing.
Remote fails to load in the host
The host shows "Something went wrong" for a remote, or the browser console reports a failed request for remoteEntry.js.
- With
@originjs/vite-plugin-federation, a remote served byvite(dev mode) does not provide/assets/remoteEntry.js. Build the remote and serve it withvite preview(the generatedpreviewscript), as shown in the Quick start. - Check the port: the host's
remotesURL must match the remote'spreview.port. Runmfe-forge syncafter changing ports. - In production, the remote URL still points at
http://localhost:<port>; see Publishing. - After fixing the cause, click Try again.
LazyRemoteandRemoteLoadercreate a new import on reset. If you use your ownReact.lazy, a rejected import stays rejected until the page reloads.
The host page is replaced by the remote's UI, or React warns about calling createRoot on a container that already has a root. The app template exposes ./App as ./src/bootstrap.tsx, which mounts into #root when imported. Expose ./src/App.tsx instead; main.tsx still loads bootstrap.tsx for standalone runs.
Events or global state do not reach other MFEs. globalEventBus and useGlobalStore are module-level state. Unless @mfe-forge/core and @mfe-forge/store are listed as singleton in shared in the host and every remote, each bundle has its own copy. See Concepts.
"Invalid hook call" or two React copies. Keep react, react-dom, react-router-dom and zustand as singletons with the same requiredVersion in every app, and install one React version across the workspace. mfe-forge deps --check reports differing versions of federation.shared dependencies among packages under packages/.
Dev server problems
dev:<scope>:<name>fails with "No packages matched the filter" or a missing workspace. The rootworkspacesglob does not includeapps/*/*. See Installation. With pnpm, addpnpm-workspace.yaml.- Only the first app starts. In multi-app mode
devrunsnpx --yes concurrently. If that fails (for example offline withoutconcurrentlyin the cache), it falls back to running scripts one after another, and the first long-running server blocks the rest. Installconcurrentlyas a dev dependency or start apps individually. --build-watchhas no effect. The flag is accepted but not implemented yet.--parallelondevis accepted but not used to limit processes.
Build and test failures
buildprints✔ built N, ✖ failed Mand exits with code2andBuild failed for: ...when any app fails. The stderr of each failed build is printed. Add--bailto stop at the first failure.build --scope xwith no apps fails withNo apps found in scope "x".buildruns each app's ownbuildscript (tsc -b && vite build), so TypeScript errors fail the build.--analyzeand--parallelare accepted onbuildbut do not change behaviour; builds run sequentially.testwith both--unitand--e2efails withUse either --unit or --e2e, not both. A failing script yieldsTests failedand exit code2.- The generated
testscript is plainvitest, which watches when run in an interactive terminal. UseCI=1 mfe-forge testfor a single run. Generated hosts do not listvitestas a dependency.
Ports
Discovery reads only the first literal port: <number> in each vite.config.ts, and allocation also reads --port <number> in dev scripts. Ports from environment variables are invisible to the CLI, so discovery reports 3000 and new apps may collide. Keep ports literal.
Package names with an organization
Set organization without the @ (acme, not @acme). The CLI prepends @ when it builds package names, so @acme produces @@acme/shop-catalog.
Still stuck
Check known issues, then open an issue with the doctor --json output, your OS, Node and package manager versions. Security problems go through SECURITY.md.