Claude Code or Cursor builds you a new feature and casually runs npm install lodash. package-lock.json jumps from 5,000 lines to 5,400. You push, CI immediately fails with npm ci: lockfile out of sync, or a teammate pulls and pnpm install --frozen-lockfile refuses. Open the conflicting file: 4,000 lines of <<<<<< / >>>>>>. Hand-merging is hopeless.
This guide gives the shortest correct path: throw away the agent’s dirty lockfile, keep the legitimate package.json changes, and regenerate a clean lockfile with the project’s actual package manager. It also explains why hand-resolving a lockfile is always wrong.
Common causes
Ordered by frequency. The first three account for ~80% of cases.
1. Agent ran npm install foo but the project uses pnpm / yarn
The classic: CLAUDE.md / AGENTS.md didn’t specify a package manager, the agent defaulted to npm install, but the repo is pnpm. Now you have a fresh package-lock.json and a stale pnpm-lock.yaml. CI flat-out rejects both.
ERR_PNPM_OUTDATED_LOCKFILE Cannot install with "frozen-lockfile"
because package-lock.json was modified
How to spot it: Two lockfiles suddenly exist (package-lock.json + pnpm-lock.yaml), or the lockfileVersion field at the top has changed.
2. AI edited package.json but never re-ran install
Aider or Codex added "axios": "^1.7.0" to dependencies but, due to a sandbox or permissions issue, never actually executed npm install. The lockfile is untouched. npm ci --frozen-lockfile blows up on CI.
npm error code EUSAGE
npm error `npm ci` can only install packages when your package.json
and package-lock.json are in sync.
How to spot it: A dependency listed in package.json does not exist anywhere in the lockfile.
3. AI ran install while local was behind main’s new deps
Your branch is three new dependencies behind main. The agent runs npm install something-else locally; npm doesn’t just install that one — it hoists and re-pins dozens of transitive deps it considered stale. 1,500 lines of unrelated lockfile churn end up in the diff and rebase explodes.
How to spot it: The lockfile diff shows additions/removals of packages you never touched.
4. AI deleted a package thinking it was unused — it was transitive
The agent grepped for import and didn’t see explicit references to tslib / regenerator-runtime / core-js, so it removed them from dependencies. Dev runs fine; production build dies because something transitively required it.
Module not found: Can't resolve 'tslib'
How to spot it: The removed package is a low-level runtime (tslib, @babel/runtime, core-js, regenerator-runtime), or npm ls <pkg> shows multiple parents.
5. AI upgraded one package and triggered peer-dep cascade
You asked the agent to bump react from 18 to 19. It dutifully re-pinned dozens of peer-dependent libs. One of them has no v19-compatible release yet, so the lockfile contains an unresolvable entry.
How to spot it: npm install reports ERESOLVE could not resolve, or the lockfile has red “unresolved” nodes.
6. Two lockfiles modified in a monorepo
Root lockfile and workspace lockfile both exist; the agent updated only one.
How to spot it: Under pnpm-workspace.yaml or package.json workspaces, two lockfile modification times are out of sync.
Shortest path to fix
Core rule: never hand-resolve a lockfile conflict — regenerate it.
Step 1: Reset the lockfile to main entirely
Don’t open the 4,000-line <<<<<< mess. Just:
git checkout origin/main -- package-lock.json
# or for pnpm / yarn
git checkout origin/main -- pnpm-lock.yaml
git checkout origin/main -- yarn.lock
Monorepo all-at-once:
git checkout origin/main -- $(git diff --name-only --diff-filter=U | grep -E '(package-lock\.json|pnpm-lock\.yaml|yarn\.lock)$')
This throws the AI’s polluted lockfile away while preserving any legitimate package.json additions.
Step 2: Audit what actually changed in package.json
git diff origin/main -- package.json
For each added dependency ask:
- Is this actually needed? Agents often add “just in case” packages.
- Is the version range what your repo uses (caret / tilde / pinned) or did the agent write
^latest? - Should it be in
dependenciesordevDependencies? (TypeScript types always go in devDeps.)
Manually delete anything that doesn’t survive that audit.
Step 3: Regenerate the lockfile with the project’s package manager
Check first:
cat package.json | grep packageManager
# e.g. "packageManager": "pnpm@9.1.0"
Then only the matching regen command:
| Manager | Regenerate command |
|---|---|
| npm | npm install --package-lock-only |
| pnpm | pnpm install --lockfile-only |
| yarn (classic) | yarn install --mode=update-lockfile |
| bun | bun install --frozen-lockfile=false |
The --*-only flag updates the lockfile without actually downloading packages — much faster, and it won’t pollute node_modules.
Step 4: Verify locally in frozen mode
rm -rf node_modules
pnpm install --frozen-lockfile # or npm ci
npm test && npm run build
frozen-lockfile / npm ci is exactly what CI runs — if it passes locally, CI will pass.
Step 5: If Step 4 reports a peer-dep error
ERESOLVE could not resolve
While resolving: react-dom@19.0.0
Found: react@18.3.1
Go back to package.json and bump or pin the conflicting side together:
# Ask the agent to look up compatible versions
# then pin manually:
npm pkg set dependencies.react=19.0.0 dependencies.react-dom=19.0.0
pnpm install --lockfile-only
Or force it with overrides / resolutions:
{
"pnpm": {
"overrides": {
"react": "19.0.0"
}
}
}
Prevention
- Pin
packageManagerinpackage.json(e.g."packageManager": "pnpm@9.1.0"); Node ≥ 16.9 will enforce it via Corepack - First line of CLAUDE.md / .cursorrules / AGENTS.md: “package manager is pnpm; never run
npm installoryarn add” - Pre-commit hook that rejects two lockfiles existing simultaneously (
package-lock.json+pnpm-lock.yaml) - When the agent wants to install a new dep, require it to say “I want X because Y” and approve before execution — keep
Bash(npm install:*)denied by default, allowlist on demand - CI must use
npm ci --frozen-lockfile/pnpm install --frozen-lockfile; any drift fails the build before it can land - Run dependency upgrades through the dedicated AI dependency upgrade workflow — don’t mix them into feature branches
Related
- AI code broke build
- Merge conflict after AI edits
- AI pre-commit review workflow
- Claude Code SEO audit
- AI dependency upgrade workflow
Tags: #AI coding #Debug #Troubleshooting