MemberJunction / MemberJunction/MJ
mj dev workspace generates strict-peer-dependencies=true for a tree with 11 pre-existing unmet peers, so every later pnpm install (and therefore every mj app install) fails
- Dominant language
- TSQL
- Stars
- 29
- Forks
- 6
- Avg merge
- 2d 1h
- Merged PRs (30d)
- 323
Description
## Summary
`mj dev workspace` writes `strict-peer-dependencies=true` into the generated `.npmrc`, but the tree it generates cannot satisfy it. MJ and `bizapps-caliber` carry pre-existing peer mismatches, so any `pnpm install` in the generated workspace that has to re-resolve fails with `ERR_PNPM_PEER_DEP_ISSUES`. In practice that means every `mj app install`.
## Environment
MJ `next`, CLI `@memberjunction/cli/6.1.0-edge.4`, Node 24.14.1, pnpm 10.33.0, macOS arm64. 17 member repos generated by `mj dev workspace`.
## What happened
The generated `.npmrc` is exactly:
```
package-manager-strict=false
strict-peer-dependencies=true
auto-install-peers=true
```
The first `pnpm install` the generator runs itself succeeds, because it writes the lockfile as it goes. Later installs succeed too, as long as nothing changes — pnpm prints `Lockfile is up to date, resolution step is skipped` and never evaluates peers.
The failure appears the moment something forces re-resolution. `mj app install` adds the app's packages to `packages/MJAPI/package.json` and `packages/MJExplorer/package.json` and then runs `pnpm install`, which re-resolves and fails:
```
ERR_PNPM_PEER_DEP_ISSUES Unmet peer dependencies
```
11 unmet peers, all pre-existing, none involving a `@mj-biz-apps/*` package:
- `@stryker-mutator/vitest-runner` wants `vitest@2`, the tree has 4
- six `bizapps-caliber` projects want `eslint@8`, the tree has 9
- `MJ/packages/AI/CorePlus` wants `date-fns@3`, the tree has 4
- `MJ/packages/AI/MCPClient` wants `express@4`, the tree has 5
- the Databricks package's `ws` peer is unsatisfied
Because `mj app install` treats a non-zero `pnpm install` as a failed step, the install finalizes the app as `Disabled` rather than `Active` and leaves the host unable to build. That was reproducible on every app until the setting was flipped.
`auto-install-peers=true` does not help here: it installs *missing* peers, and every one of these is a *mismatched* peer.
## Root cause
`NPMRC_BASE_LINES` in `packages/MJCLI/src/lib/dev-workspace/build.ts:73-77` hardcodes the three lines, and `BuildNpmrc` (`build.ts:225-227`) emits them verbatim. The command writes the file at `packages/MJCLI/src/commands/dev/workspace/index.ts:174`.
The setting is a reasonable default in the abstract. The problem is that the generator has no way to know whether the joined tree can satisfy it, and it does not check. The union of N repos' dependency graphs is strictly more peer-constrained than any one of them: each repo's own CI only ever resolves its own graph, so a mismatch between two repos, or between a repo and a hoisted devDependency, is invisible until the generator joins them. The generator already unions and reports `pnpm.overrides`, `patchedDependencies`, `packageExtensions` and `peerDependencyRules` conflicts across members (`ResolveMemberPnpmBlocks`, `build.ts:448-484`) — peer satisfiability is the one cross-member property it asserts without measuring.
The failure mode is also unusually confusing because it is delayed. The setting is latent until an unrelated command happens to force re-resolution, and the error then names packages the developer was not touching.
## Workaround
Set `strict-peer-dependencies=false` in the generated `.npmrc`. Every app install then completes `Active` on the first pass. The edit is lost on any `mj dev workspace` regeneration.
## Notes
Options range from the generator emitting `false` (or emitting it conditionally when it detects an unsatisfiable union), to fixing the underlying peer ranges in MJ and `bizapps-caliber`, to generating targeted `peerDependencyRules.allowedVersions` entries for the known mismatches. Happy to send a PR for whichever you prefer.
Contributor guide
Research direction
Read NPMRC_BASE_LINES and BuildNpmrc in packages/MJCLI/src/lib/dev-workspace/build.ts, then trace the write in packages/MJCLI/src/commands/dev/workspace/index.ts. Reproduce the generated workspace install and mj app install behavior, including peer resolution. Done means the chosen strict-peer-dependency policy is generated consistently and later installs no longer fail on the reported pre-existing peers.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- build-system, cli, devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100