npm install ya da npm ci komutu ERESOLVE koduyla duruyor ve ekrana "Found", "peer" ve "Could not resolve dependency" satırlarından oluşan uzun bir blok basıyor. Makinenizde bir arıza yok. npm, projenizde aynı anda karşılanamayan sürüm gereksinimleri buldu ve bunlardan birini sessizce çiğnemek yerine kurulumu durdurdu. Bu rehberde raporu okumayı, çakışmanın kaynağı olan paketi bulmayı ve ekip arkadaşlarınızın kurulumunu ya da CI hattınızı bozmayacak çözümü seçmeyi adım adım anlatıyoruz. Aşağıdaki çıktıların hepsini Ekim 2026'da Node.js 22 üzerinde, npm kayıt deposundaki (registry) gerçek paketlerle ürettik: güncel biçim için npm 10.9, eski biçim için npm 8.19 kullandık.
Hata mesajı
Örnek proje React 19 kullanıyor ve react-beautiful-dnd paketine de bağımlı. npm 10.6.0'dan (Nisan 2024) itibaren her satır npm error ile başlar:
Code:
$ npm install
npm error code ERESOLVE
npm error ERESOLVE unable to resolve dependency tree
npm error
npm error While resolving: [email protected]
npm error Found: [email protected]
npm error node_modules/react
npm error react@"^19.2.0" from the root project
npm error
npm error Could not resolve dependency:
npm error peer react@"^16.8.5 || ^17.0.0 || ^18.0.0" from [email protected]
npm error node_modules/react-beautiful-dnd
npm error react-beautiful-dnd@"^13.1.1" from the root project
npm error
npm error Fix the upstream dependency conflict, or retry
npm error this command with --force or --legacy-peer-deps
npm error to accept an incorrect (and potentially broken) dependency resolution.
npm error
npm error
npm error For a full report see:
npm error /home/dev/.npm/_logs/2026-10-27T00_40_38_025Z-eresolve-report.txt
npm error A complete log of this run can be found in: /home/dev/.npm/_logs/2026-10-27T00_40_38_025Z-debug-0.log
Daha eski sürümler satır başına npm ERR! yazar. Eski forum yazılarında ve soru-cevap sitelerinde hâlâ karşınıza çıkan npm 8 çıktısı şöyledir:
Code:
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR! react@"^18.2.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.9.0 || ^17.0.0" from @testing-library/[email protected]
npm ERR! node_modules/@testing-library/react-hooks
npm ERR! dev @testing-library/react-hooks@"^8.0.1" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /home/dev/.npm/eresolve-report.txt for a full report.
npm ERR! A complete log of this run can be found in:
npm ERR! /home/dev/.npm/_logs/2026-10-27T04_40_18_151Z-debug-0.log
| npm sürümü | Satır öneki | Tam rapor dosyası |
|---|---|---|
| 7 ve 8 | npm ERR! | ~/.npm/eresolve-report.txt (her hatada üzerine yazılır) |
| 9.0 – 10.5 | npm ERR! | ~/.npm/_logs/ZAMAN-eresolve-report.txt |
| 10.6 ve sonrası (11 ve 12 dahil) | npm error | ~/.npm/_logs/ZAMAN-eresolve-report.txt |
Windows'ta önbellek (cache) %LocalAppData%\npm-cache klasöründedir; log dosyaları da %LocalAppData%\npm-cache\_logs altına yazılır. Raporun yanındaki ZAMAN-debug-0.log dosyası çalıştırmanın her adımını kaydeder ve npm varsayılan olarak en yeni 10 log dosyasını saklar. Hangi satırın sizin için geçerli olduğunu npm -v gösterir.
Hatanın ikinci bir biçimi de var. Testlerimizde bu biçim, --legacy-peer-deps ya da --force ile oluşturulmuş bir kilit dosyası (lockfile) bayraksız kurulduğunda ortaya çıktı; npm install ve npm ci aynı çıktıyı verdi. Başlık "could not resolve" olur ve npm'in eklemek istediği sürümü gösteren ek bir blok belirir (kapanış satırları ilk örnekle aynıdır):
Code:
npm error code ERESOLVE
npm error ERESOLVE could not resolve
npm error
npm error While resolving: [email protected]
npm error Found: [email protected]
npm error node_modules/react
npm error react@"^19.2.0" from the root project
npm error peer react@"^19.3.1" from [email protected]
npm error node_modules/react-dom
npm error react-dom@"^19.2.0" from the root project
npm error
npm error Could not resolve dependency:
npm error peer react@"^16.8.5 || ^17.0.0 || ^18.0.0" from [email protected]
npm error node_modules/react-beautiful-dnd
npm error react-beautiful-dnd@"^13.1.1" from the root project
npm error
npm error Conflicting peer dependency: [email protected]
npm error node_modules/react
npm error peer react@"^16.8.5 || ^17.0.0 || ^18.0.0" from [email protected]
npm error node_modules/react-beautiful-dnd
npm error react-beautiful-dnd@"^13.1.1" from the root project
Neden oluyor: peer dependency kavramı
Normal bir bağımlılık, paketin yanında getirdiği koddur. peerDependencies alanında tanımlanan eş bağımlılık (peer dependency) ise başka bir şey söyler: "Bu paketi kendim getirmiyorum; projenizde zaten kurulu olan kopyayı kullanıyorum ve o kopyanın sürümü şu aralıkta olmalı." Eklentiler ve arayüz kütüphaneleri bu yöntemi genişlettikleri ana paket için kullanır: bir React bileşen kütüphanesi react'i, bir ESLint eklentisi eslint'i, bir Angular kütüphanesi @angular/core'u peer olarak tanımlar. Bir uygulamada tek bir React bulunmalıdır; kütüphanenin kendine ait ikinci bir kopya getirmesi bu kuralı bozar.npm 3–6 peer bağımlılıkları kurmazdı; sürüm uymadığında yalnızca uyarı verirdi ve pek çok proje bu uyarıları yıllarca taşıdı. npm 7 (Ekim 2020) ile birlikte peer'lar otomatik kurulur ve npm her peer aralığını karşılayan bir ağaç kurmaya çalışır. Çakışma sizin package.json dosyanızı, raporun deyişiyle "the root project"i ilgilendiriyorsa geçerli bir ağaç yoktur ve npm ERESOLVE ile durur. Ağacın derinlerindeki çakışmalarda npm daha esnektir: en yakın normal bağımlılığa bakarak bir sürüm seçer ve kurulumu durdurmak yerine "npm warn ERESOLVE overriding peer dependency" uyarısı basar. strict-peer-deps=true ayarı bu uyarıları da hataya çevirir.
Peer aralıkları semver (anlamsal sürümleme) kurallarıyla yazılır. Aşağıdaki sonuçları npm'in kendi kullandığı semver kütüphanesiyle doğruladık:
| Aralık | Kabul ettiği | Reddettiği (örnek) |
|---|---|---|
| ^1.2.3 | 1.2.3 ve üstü, 2.0.0'ın altı | 2.0.0 |
| ~1.2.3 | 1.2.3 ve üstü, 1.3.0'ın altı | 1.3.0 |
| ^0.2.3 | 0.2.3 ve üstü, 0.3.0'ın altı | 0.3.0 |
| ^16.8.0 || ^17.0.0 | 16.8 ve sonraki 16.x, tüm 17.x | 18.0.0 |
| >=4.8.4 <6.1.0 | 4.8.4'ten 6.0.x'e kadar | 7.0.2 |
| ^18.0.0 || ^19.0.0 | kararlı 18.x ve 19.x | 19.0.0-rc.1, canary sürümleri |
Son satır çoğu kişiyi şaşırtır: ön sürümler (rc, beta, canary), ana sürüm (major) tutsa bile sıradan bir aralığı karşılamaz. Projeniz bir React canary sürümüne sabitlenmişse React 19'u destekleyen kütüphaneler bile ERESOLVE verir. Aralıkları npm semver hesaplayıcısında deneyebilirsiniz.
Raporu okumak: adım adım örnek
Raporu yukarıdan aşağı okuyun; her blok tek bir soruyu yanıtlar:- While resolving: npm hangi paketin bağımlılıklarını yerleştiriyordu? [email protected], kendi package.json dosyanızdaki ad ve sürümdür. İkinci biçimde ise peer'ı yerleştirilemeyen pakettir.
- Found: ağaçta zaten ne var ([email protected]) ve onu kim istedi? "from the root project" sizin package.json dosyanız demektir; satır başındaki "dev" ise bunun bir devDependency olduğunu gösterir.
- Could not resolve dependency: karşılanamayan gereksinim. [email protected] yalnızca React 16.8.5 ve sonraki 16.x, 17 ya da 18 kabul ediyor.
- Conflicting peer dependency (yalnızca ikinci biçimde): o aralığı karşılamak için npm'in eklemesi gereken sürüm. Bu örnekte o sürüm, aralığa uyan en yeni sürüm olan [email protected]'dir.
Tek cümleyle: projeniz React 19 istiyor, react-beautiful-dnd 13.1.1 ise React 18'de kalıyor. Bunu doğrulamak ve çıkış yolu aramak için yalnızca okuma yapan komutlar yeterli:
Bash:
# paket hangi peer'ları tanımlıyor, kullanımdan kaldırılmış mı?
npm view react-beautiful-dnd peerDependencies
npm view react-beautiful-dnd deprecated
# sürümler boyunca peer aralığı: ana sürümünüzü kabul eden ilk sürümü bulun
npm view "@hello-pangea/dnd@>=16" peerDependencies.react
# bir paket neden ve hangi zincirle kurulmuş? (node_modules gerekir)
npm explain react
# tüm ağaç; aralık dışında kalan peer'lar "invalid" diye işaretlenir
npm ls react --all
İkinci komut Atlassian'ın notunu döndürdü: react-beautiful-dnd kullanımdan kaldırılmış (deprecated); paketin GitHub deposu da arşivlenmiş durumda. Aralık sorgusu ise topluluk tarafından sürdürülen bir çatal (fork) olan @hello-pangea/dnd paketinin 18.0.0'dan itibaren "^18.0.0 || ^19.0.0" kabul ettiğini gösterdi. Gerçek çözüm bir bayrak değil, budur.
Aynı desen ekosistemin her yerinde karşınıza çıkar. Aşağıdaki çakışmalar Ekim 2026'da npm kayıt deposunda geçerliydi. Peer aralıkları her sürümle değişebileceği için harekete geçmeden önce npm view ile yeniden kontrol edin:
| Projeniz | Paket ve peer aralığı | Pratik çözüm |
|---|---|---|
| React 19 | react-beautiful-dnd 13.1.1: react ^16.8.5 || ^17 || ^18 (kullanımdan kaldırıldı) | @hello-pangea/dnd 18.x, dnd-kit ya da Pragmatic drag and drop |
| React 18 veya 19 | @testing-library/react-hooks 8.0.1: react ^16.9.0 || ^17.0.0 | @testing-library/react 13.1+ içindeki renderHook |
| ESLint 10 | eslint-plugin-react 7.37.5: eslint en fazla ^9.7 | Eklenti ESLint 10 desteğini yayımlayana kadar ESLint 9 |
| TypeScript 7 | typescript-eslint 8.72.1: typescript >=4.8.4 <6.1.0 | Şimdilik TypeScript 6.0.x |
| Angular 22 ve TypeScript 7 | @angular/compiler-cli 22.2.3: typescript >=6.0 <6.1 | Angular'ın desteklediği TypeScript sürümü; yükseltme için ng update |
ESLint satırı yalnızca bir sürüm kuralı değil. Peer kontrolünü atlayıp eslint-plugin-react 7.37.5'i ESLint 10.13 ile kurduğumuzda kurulum tamamlandı; ancak React sürümünü otomatik algılayan (version: "detect") bir yapılandırmada lint komutu "TypeError: Error while loading rule 'react/display-name': contextOrFilename.getFilename is not a function" hatasıyla çöktü. Sebep, eklentinin hâlâ çağırdığı context.getFilename() yönteminin ESLint 10'da kaldırılmış olması. Bu örnek, ERESOLVE hatasını susturmanın çakışmayı çözmekle aynı şey olmadığını açıkça gösteriyor.
Bu çakışmaların önemli bir kısmının arkasında React vardır, çünkü neredeyse her bileşen kütüphanesi onu peer olarak tanımlar. Yükseltmenin genel resmi için React 2026 üretim notlarımıza göz atabilirsiniz.
Çözümler: tercih sırasıyla
| Durum | Çözüm | Risk |
|---|---|---|
| Paketin yeni bir sürümü sizin sürümünüzü zaten kabul ediyor | 1. O paketi yükseltin | Düşük |
| Ana paketi (ESLint, TypeScript, React) eklentileri yetişmeden yükselttiniz | 2. Sürümleri hizalayın | Düşük |
| Paket kullanımdan kalkmış, arşivlenmiş ya da yıllardır güncellenmiyor | 3. Paketi değiştirin | Geçiş emeği |
| Tek bir paketin peer aralığı eskimiş ve testleriniz geçiyor | 4. overrides (npm 8.3+) ya da packageExtensions (npm 12+) | Orta; ama görünür ve sınırlı |
| Çok sayıda eski peer aralığı var ve bugün teslim etmeniz gerekiyor | 5. Depoya işlenmiş .npmrc ile legacy-peer-deps | Yüksek; tüm peer kontrollerini kapatır |
| Başka hiçbir yol kalmadı | 6. --force | En yüksek |
1. Eski peer tanımlayan paketi yükseltin
Önce en son sürüme bakın: npm view @testing-library/react peerDependencies. 12.1.5 sürümü react <18.0.0 tanımladığı için React 18 projesinde hata verir; 16.1.0 ve sonrası ise ^18.0.0 || ^19.0.0 kabul eder. Bu tür yükseltmeler çoğunlukla ana sürüm atlamasıdır, bu yüzden değişiklik günlüğünü (changelog) ya da geçiş rehberini okuyun. Güncel 16.x sürümleri @testing-library/dom ^10 paketini de peer olarak ister; onu devDependencies'e açıkça ekleyin:
Bash:
npm install -D @testing-library/react@latest @testing-library/dom@latest
2. Kendi sürümlerinizi hizalayın
Ana paketi kısa süre önce yeni bir major sürüme geçirdiyseniz en zahmetsiz çözüm çoğu zaman eklentiler yetişene kadar bir adım geri dönmektir:
Bash:
npm install -D eslint@9 # eslint-plugin-react ESLint 10'u tanımlayana kadar
npm install -D typescript@~6.0 # typescript-eslint TypeScript 7'yi kabul edene kadar
Birbirine bağlı paketleri birlikte yükseltin: react, react-dom, @types/react ve @types/react-dom tek bir birim gibi hareket eder. Angular paketleri birbirini birebir sürümle ister (@angular/core 22.2.3, @angular/compiler 22.2.3'ü bekler) ve derleyici yalnızca TypeScript >=6.0 <6.1 kabul eder. Bu yüzden paketleri tek tek yükseltmek yerine ng update @angular/core @angular/cli komutunu kullanın.
3. Terk edilmiş paketi değiştirin
Kullanımdan kaldırılmış, arşivlenmiş ya da yıllardır yeni sürüm çıkmamış bir paketin peer aralığını genişletmesini beklemeyin. @testing-library/react-hooks paketinin son sürümü olan 8.0.1 (Haziran 2022) hâlâ React ^16.9.0 || ^17.0.0 tanımlıyor; README dosyası React 18 ve sonrası için @testing-library/react 13.1 ile gelen renderHook işlevini gösteriyor. Senkron testlerde geçiş çoğunlukla import satırını değiştirmekten ibarettir. Ancak yeni renderHook yalnızca result, rerender ve unmount döndürür; waitForNextUpdate, waitForValueToChange ve result.all yoktur. Bunları kullanan testleri @testing-library/react içindeki waitFor ile yeniden yazmanız gerekir. react-beautiful-dnd için Atlassian'ın kullanımdan kaldırma notu şu seçenekleri sıralıyor: paketin bir çatalına geçmek (örneğin @hello-pangea/dnd), dnd-kit gibi benzer bir kütüphaneye geçmek ya da Atlassian'ın kendi Pragmatic drag and drop çözümünü kullanmak.4. Tek bir bağımlılığı bilerek geçersiz kılın (overrides)
Bir paketin peer aralığı yalnızca eskimişse ve testleriniz yeni ana sürümle geçiyorsa bunu package.json dosyasında açıkça belirtin. overrides alanı npm 8.3.0 ve sonrasında, yalnızca kök package.json dosyasında çalışır:
Code:
{
"dependencies": {
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-beautiful-dnd": "^13.1.1"
},
"overrides": {
"react-beautiful-dnd": {
"react": "$react",
"react-dom": "$react-dom"
}
}
}
"$react" ifadesi "doğrudan bağımlılığım olan react ile aynı tanımı kullan" anlamına gelir. Doğrudan bağımlı olduğunuz bir paket için farklı bir sürüm yazamazsınız: npm EOVERRIDE ile durur ("Override for react@^19.2.0 conflicts with direct dependency") ve belgelenmiş çıkış yolu $ referansıdır. Kuralı react-beautiful-dnd altına yerleştirmek, etkisini o paket ve onun bağımlılıklarıyla sınırlar. npm install sonrasında npm ls react --all ilgili paketleri "invalid" yerine "overridden" olarak işaretler. Override yalnızca sürüm kontrolünü susturur, eski kodu uyumlu hâle getirmez: testleri çalıştırın, gerekçeyi pull request açıklamasına yazın ve paket desteği yayımladığında override'ı kaldırın. Örnekteki react-beautiful-dnd aslında bu koşulu karşılamıyor: Droppable bileşeninin varsayılan değerlerini (type, direction, mode) memo ile sarılmış bir fonksiyon bileşenine defaultProps olarak veriyor, React 19 ise fonksiyon bileşenlerinde defaultProps desteğini kaldırdı. Override kurulumu geçirir, ama bu paket için doğru yol 3. adımdaki geçiştir; örneği yalnızca sözdizimini göstermek için kullandık.
npm 12 (Temmuz 2026) packageExtensions alanını ekledi. Bu alan, bir bağımlılığın manifest bilgisini çözümlemeden önce onarır: eksik bir bağımlılık ekleyebilir ya da peerDependencies içindeki bir aralığı yenisiyle değiştirebilirsiniz. Onarım package-lock.json dosyasına kaydedilir, npm ls ve npm explain çıktısında da görünür. Örnekteki old-eslint-plugin temsili bir paket adıdır:
Code:
{
"packageExtensions": {
"old-eslint-plugin@2": {
"peerDependencies": { "eslint": "^9.0.0 || ^10.0.0" }
}
}
}
Bu yöntemi eslint-plugin-react 7.37.5 için kullanmayın: yukarıda gördüğümüz gibi kurulum geçer, ama ESLint 10 ile lint aşaması çöker. overrides gibi packageExtensions da yalnızca kök package.json dosyasında dikkate alınır ve npm, bu alanı içeren ve özel (private) olarak işaretlenmemiş bir paketi yayımlamayı reddeder. İki alanın ayrıntıları package.json başvuru belgesinde yer alıyor.
5. --legacy-peer-deps: ancak ekip kararıyla
Bu bayrak, npm 3–6'da olduğu gibi ağacı kurarken peerDependencies alanını tamamen yok sayar. Eksik peer'ları kurmaz, yalnızca sorunlu pakete değil bütün ağaca uygulanır ve npm'in kendi belgeleri de kullanılmasını önermez. Kullanacaksanız herkes kullanmalıdır: bu bayrakla oluşturulan kilit dosyası, bayraksız çalışan npm install ya da npm ci komutunda "ERESOLVE could not resolve" hatası verir. Ayarı projeye kaydedin:
Bash:
npm config set legacy-peer-deps=true --location=project
cat .npmrc
# legacy-peer-deps=true
git add .npmrc package-lock.json
Çakışmalar ortadan kalkmaz, yalnızca gizlenir: npm ls --all onları hâlâ "invalid" diye listeler ve ELSPROBLEMS koduyla çıkar. Yazıma da dikkat edin. npm 10, --legacy-peers-deps gibi bilinmeyen bir bayrağı hiçbir uyarı vermeden yok sayar; aynı hatayı yeniden görünce bayrağın işe yaramadığını sanırsınız. Daha yeni npm 11 sürümleri bilinmeyen bayraklar için uyarı verir, npm 12 ise bunları reddeder.
6. --force: son çare
--force peer çözümlemesini kapatmaz ama çakışan peer'ları kök projeye kabul eder. Ekranda "npm warn ERESOLVE overriding peer dependency" blokları görürsünüz ve kilit dosyasına tanımlı aralığın dışında bir peer yazılır. Aynı bayrak başka korumaları da kaldırır: engines kontrollerini yok sayar ve npm audit fix komutunun major sürüm değişiklikleri kurmasına izin verir. npm belgeleri bunu açıkça söyler: ne yapmak istediğinizi tam olarak bilmiyorsanız bu seçeneği kullanmayın. Karar package.json dosyasında hiçbir yere kaydedilmediği için bir sonraki bayraksız kurulum yine hata verir.7. Bilinçli temiz kurulum
Temiz kurulum gerçek bir çakışmayı çözmez. Ancak dal (branch) değiştirdikten, yarıda kalan bir kurulumdan ya da kötü birleştirilmiş bir package-lock.json dosyasından sonra node_modules veya kilit dosyası bozulduysa işe yarar:
Bash:
rm -rf node_modules
npm install # mevcut kilit dosyasından yeniden kur
npm ls --all # hâlâ invalid ya da missing var mı?
# yalnızca her şeyi yeniden çözümlemeye karar verirseniz:
git switch -c chore/regenerate-lockfile
rm -rf node_modules package-lock.json
npm install
git diff --stat package-lock.json
Kilit dosyasını node_modules ile birlikte silmek, her bağımlılığı aralığının izin verdiği en yeni sürüme taşır; bu yüzden bunu ayrı bir dalda yapın ve bütün testleri çalıştırın. Yalnızca package-lock.json dosyasını silmek yetmez: testimizde npm, node_modules içinde bulduğu eski sürümü korudu ve aralıktaki en yeni sürümü ancak ikisi birlikte silindiğinde kurdu. Önbelleği temizlemek (npm cache clean --force) peer çözümlemesini değiştirmez; önbelleğin bozulduğundan şüpheleniyorsanız npm cache verify yeterlidir.
CI ve Docker
CI hatlarında (pipeline) npm ci kullanın. Bu komut package-lock.json dosyası ister, kurulumdan önce node_modules klasörünü siler, package.json ya da kilit dosyasına hiç yazmaz ve ikisi uyuşmuyorsa "Missing: [email protected] from lock file" gibi satırlarla EUSAGE hatası verir. Dizüstü bilgisayarınızda sorunsuz kurulan proje CI ortamında ERESOLVE veriyorsa şunlara bakın:- Kilit dosyası birinin makinesinde --legacy-peer-deps ya da --force ile üretilmiş, CI ise bayraksız çalışıyor. npm ci belgeleri aynı bayrakların verilmesi gerektiğini söyler; depoya işlenmiş bir .npmrc dosyası bunu sizin yerinize yapar.
- Docker: Dockerfile yalnızca package.json ve package-lock.json dosyalarını kopyalıyorsa npm ci çalışırken .npmrc imajda bulunmaz. Onu da kopyalayın. Kayıt deposu token'larını proje .npmrc dosyasında tutmayın; derleme sırları (build secrets) ya da ortam değişkenleriyle verin.
- Farklı npm ana sürümleri peer'ları her zaman aynı biçimde çözümlemez. Node.js 22 npm 10.9 ile, Node.js 24 ve 26 npm 11 ile gelir; npm 12 ayrıca kurulur ve Node.js ^22.22.2, ^24.15.0 ya da 26 ve üstünü ister. Node sürümünü sabitleyin.
YAML:
# .github/workflows/ci.yml (kesit)
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
cache: npm
- run: npm ci
- run: npm ls --all # ağaç temizlendikten sonra gizli çakışmaları yakalar
- run: npm test
Code:
# Dockerfile (kesit)
FROM node:24-slim
WORKDIR /app
# projede .npmrc yoksa bir sonraki satırdan çıkarın
COPY package.json package-lock.json .npmrc ./
RUN npm ci
COPY . .
npm ls --all adımını ağacınızı temizledikten sonra ekleyin. Testimizde seçeneksiz npm ls, gizli peer çakışmalarına rağmen 0 koduyla çıktı; npm ls --all ise 1 döndürdü. Bilinçli olarak eklenmiş bir override ise kontrolü geçti. Sürümleri sabitlemek için:
- .nvmrc dosyasına ana sürümü yazın (örneğin 24). nvm, fnm ve setup-node'un node-version-file girdisi bu dosyayı okur. Node.js 24 bir LTS sürümüdür; Node.js 26 ise 28 Ekim 2026'da LTS olur.
- package.json içindeki engines alanı ("node": ">=24") tek başına yalnızca EBADENGINE uyarısı üretir; .npmrc dosyasına engine-strict=true eklerseniz uyarı hataya dönüşür.
- devEngines alanı (npm 10.9+) install, ci ve run komutlarından önce çalışma ortamını ve paket yöneticisini denetler; uyuşmazlıkta EBADDEVENGINES hatası verir.
- Yarn ya da pnpm kullanıyorsanız sürümü package.json içindeki packageManager alanıyla sabitleyebilirsiniz; bu alanı Corepack okur. Corepack, Node.js 14.19 ile 24.x arasındaki sürümlerle birlikte gelir; Node.js 25 ve sonrasında npm install -g corepack ile ayrıca kurmanız gerekir.
Yarn ve pnpm'de karşılıkları
İki araç da varsayılan olarak peer uyuşmazlığında kurulumu durdurmaz; uyarı verip devam eder. Yani aynı sorun, gözden kaçması kolay bir uyarı olarak karşınıza çıkar.- Yarn (1.x ve 4.x): kök package.json içindeki resolutions alanıyla bir sürümü sabitlersiniz. Yarn 4 uyumsuz bir peer'ı YN0060 INCOMPATIBLE_PEER_DEPENDENCY olarak bildirir; Yarn belgelerine göre bu durum çözümlemeyi engellemez ama sistemi hatalı bir durumda bırakabilir. Ayrıntı için uyarıdaki p harfiyle başlayan kodu yarn explain peer-requirements komutuna verin. .yarnrc.yml içindeki packageExtensions eksik bağımlılık eklemek içindir; mevcut bir tanımı değiştirmek için Yarn resolutions alanını önerir.
- pnpm: varsayılan davranış uyarıdır; strictPeerDependencies: true uyarıları hataya çevirir. pnpm 11'den itibaren bu ayarlar pnpm-workspace.yaml dosyasında yer almalıdır; package.json içindeki "pnpm" alanı artık okunmaz (pnpm 10 ve öncesi bu alanı da kabul ediyordu). pnpm'in overrides alanı peer bağımlılıklara da uygulanır. Aşağıdaki örnekte old-ui-kit ve old-eslint-plugin temsili paket adlarıdır.
YAML:
# pnpm-workspace.yaml (pnpm 11 ve sonrası)
strictPeerDependencies: false # varsayılan; true peer uyarılarını hataya çevirir
peerDependencyRules:
allowedVersions:
"old-ui-kit>react": "19" # yalnızca uyarıyı susturur
overrides:
"old-eslint-plugin>eslint": "^10.0.0" # peer aralığını yeniden yazar
Önleme: çakışmayı baştan engellemek
- npm outdated komutunu düzenli çalıştırın; Wanted ve Latest sütunları bekleyen major yükseltmeleri gösterir.
- Bir ana paketin (React, ESLint, TypeScript, Angular) yeni major sürümüne geçmeden önce eklentilerinin peer aralıklarını npm view ile kontrol edin.
- Aileleri tek bir pull request içinde yükseltin: react + react-dom + @types/react + @types/react-dom; eslint + eklentileri + typescript-eslint; Angular için ng update.
- Ön sürümleri (rc, canary) uygulamalarda ancak doğuracakları peer çakışmalarını yönetmeye hazırsanız kullanın.
- Güncelleme botunuzun bu aileleri grup hâlinde açmasını sağlayın. Dependabot için .github/dependabot.yml, Renovate için renovate.json örneği:
YAML:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
groups:
react:
patterns: ["react", "react-dom", "@types/react", "@types/react-dom"]
eslint:
patterns: ["eslint", "eslint-*", "@eslint/*", "typescript-eslint"]
Code:
{
"extends": ["config:recommended"],
"packageRules": [
{
"matchPackageNames": ["react", "react-dom", "@types/react", "@types/react-dom"],
"groupName": "react"
}
]
}
İlgili npm hataları
| Kod | Tipik mesaj | Ne yapmalı |
|---|---|---|
| ETARGET | No matching version found for react@99. | İstenen sürüm ya da etiket yok: yazım hatası, yayımdan kaldırılmış bir sürüm ya da paketi barındırmayan özel bir kayıt deposu. npm view PAKET versions ile kontrol edin. |
| EACCES | permission denied; genellikle npm install -g komutu /usr/local/lib/node_modules gibi bir sistem klasörüne yazarken | sudo kullanmayın. Node'u nvm ya da fnm gibi bir sürüm yöneticisiyle kurun veya npm'in global önekini (prefix) size ait bir klasöre taşıyın; npm'in bu konuda resmî bir rehberi var. |
| ENOENT | Could not read package.json (npm run, npm start, npm test gibi komutlarda) | Yanlış klasördesiniz ya da proje hiç başlatılmamış: package.json dosyasının bulunduğu klasöre geçin veya npm init çalıştırın. |
| EBADENGINE, EBADDEVENGINES | Unsupported engine; Invalid engine "runtime" | Node ya da npm sürümünüz projenin veya bir paketin tanımladığı aralığın dışında; sürüm yöneticinizle doğru sürüme geçin. |
| EUSAGE (npm ci) | package.json ile package-lock.json uyumsuz; Missing: … from lock file | Yerelde npm install çalıştırıp güncellenen kilit dosyasını depoya işleyin. |
| EOVERRIDE | Override for react@^19.2.0 conflicts with direct dependency | $ referansını ("react": "$react") ya da birebir aynı tanımı kullanın. |
Sık sorulan sorular
--legacy-peer-deps güvenli mi?Kurulumun kendisini bozmaz; ama peer kontrollerini bütün ağaç için kapattığından gerçek bir uyumsuzluk ancak çalışma zamanında (runtime) ortaya çıkabilir. Geçici bir köprü olarak kullanın, .npmrc ile bütün ekibe yayın ve kalan sorunları npm ls --all ile izleyin.
--force mu, --legacy-peer-deps mi?
İkisi de kalıcı çözüm değil. Mecbursanız --legacy-peer-deps daha öngörülebilirdir: tek bir iş yapar ve .npmrc ile kayıt altına alınabilir. --force ise aynı anda başka korumaları da kaldırır.
package-lock.json dosyasını silmeli miyim?
Refleks olarak hayır. Gerçek bir peer çakışmasını çözmez, üstelik bütün bağımlılıkları yeniden çözümler. Gerekiyorsa ayrı bir dalda yapın ve farkı inceleyin.
Neden benim makinemde çalışıyor da CI ortamında ya da Docker'da çalışmıyor?
Genellikle yerelde kullanılan bir bayrak CI ortamına taşınmamıştır, .npmrc imaja kopyalanmamıştır ya da npm sürümleri farklıdır. Ayarı .npmrc dosyasına yazın, dosyayı Docker imajına kopyalayın ve Node sürümünü sabitleyin.
npm önbelleğini temizlemek işe yarar mı?
ERESOLVE için hayır. Hata, sürüm aralıklarının mantığından kaynaklanır; önbellekteki dosyalar sonucu değiştirmez.
Sonuç ve sonraki adımlar
ERESOLVE, npm'in "bu iki gereksinimi aynı anda karşılayamam" deme biçimidir. Raporu okuyun, peer aralığını npm view ile doğrulayın ve çözümleri sırasıyla deneyin: paketi yükseltin, sürümleri hizalayın, terk edilmiş paketi değiştirin; bunlar mümkün değilse kapsamı belli bir override kullanın. Bayraklara alışkanlıkla değil, kayıt altına alınmış bir ekip kararıyla başvurun. Sıradaki adımlar: npm ls --all çıktısını temizleyin, .nvmrc ve gerekiyorsa .npmrc dosyasını depoya işleyin ve güncelleme botunuzda React ile ESLint ailelerini gruplayın. Node.js servislerinin sunucu tarafını ele aldığımız Node.js backend yazımız bir sonraki okuma olabilir. Bağımlılık yükseltmelerini planlamak ya da büyük bir kod tabanını taşımak için destek arıyorsanız AIOR'un yazılım mühendisliği hizmetleri seçeneklerden biri. Takıldığınız noktada kendi hata çıktınızı bu konuya yapıştırabilirsiniz.npm install or npm ci stops with code ERESOLVE and a wall of text about "Found", "peer" and "Could not resolve dependency". Your machine is fine. npm has found version requirements in your project that cannot all be met at once, and instead of quietly breaking one of them, it stops. This guide shows how to read the report, find the package behind the conflict and choose a fix that won't break your teammates' installs or your CI pipeline. We produced every output below on Node.js 22 in October 2026 with real packages from the public npm registry, using npm 10.9 for the current format and npm 8.19 for the old one.
The error message
The example project uses React 19 and also depends on react-beautiful-dnd. Since npm 10.6.0 (April 2024), every line starts with npm error:
Code:
$ npm install
npm error code ERESOLVE
npm error ERESOLVE unable to resolve dependency tree
npm error
npm error While resolving: [email protected]
npm error Found: [email protected]
npm error node_modules/react
npm error react@"^19.2.0" from the root project
npm error
npm error Could not resolve dependency:
npm error peer react@"^16.8.5 || ^17.0.0 || ^18.0.0" from [email protected]
npm error node_modules/react-beautiful-dnd
npm error react-beautiful-dnd@"^13.1.1" from the root project
npm error
npm error Fix the upstream dependency conflict, or retry
npm error this command with --force or --legacy-peer-deps
npm error to accept an incorrect (and potentially broken) dependency resolution.
npm error
npm error
npm error For a full report see:
npm error /home/dev/.npm/_logs/2026-10-27T00_40_38_025Z-eresolve-report.txt
npm error A complete log of this run can be found in: /home/dev/.npm/_logs/2026-10-27T00_40_38_025Z-debug-0.log
Older releases start each line with npm ERR! instead. This is the npm 8 version of the same failure, the one you will still find in older forum threads and Q&A answers:
Code:
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR! react@"^18.2.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.9.0 || ^17.0.0" from @testing-library/[email protected]
npm ERR! node_modules/@testing-library/react-hooks
npm ERR! dev @testing-library/react-hooks@"^8.0.1" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /home/dev/.npm/eresolve-report.txt for a full report.
npm ERR! A complete log of this run can be found in:
npm ERR! /home/dev/.npm/_logs/2026-10-27T04_40_18_151Z-debug-0.log
| npm version | Line prefix | Full report |
|---|---|---|
| 7 and 8 | npm ERR! | ~/.npm/eresolve-report.txt, overwritten on every failure |
| 9.0 to 10.5 | npm ERR! | ~/.npm/_logs/TIMESTAMP-eresolve-report.txt |
| 10.6 and later (11 and 12 included) | npm error | ~/.npm/_logs/TIMESTAMP-eresolve-report.txt |
On Windows the cache is %LocalAppData%\npm-cache, so the logs land in %LocalAppData%\npm-cache\_logs. The debug log next to the report (TIMESTAMP-debug-0.log) records every step of the run, and npm keeps the ten newest log files by default. Run npm -v to see which row applies to you.
There is a second form. In our tests it appeared when a lockfile created with --legacy-peer-deps or --force was installed without the flag, and npm install and npm ci printed the same thing. The headline changes to "could not resolve" and an extra block names the version npm wanted to add (the closing lines match the first example):
Code:
npm error code ERESOLVE
npm error ERESOLVE could not resolve
npm error
npm error While resolving: [email protected]
npm error Found: [email protected]
npm error node_modules/react
npm error react@"^19.2.0" from the root project
npm error peer react@"^19.3.1" from [email protected]
npm error node_modules/react-dom
npm error react-dom@"^19.2.0" from the root project
npm error
npm error Could not resolve dependency:
npm error peer react@"^16.8.5 || ^17.0.0 || ^18.0.0" from [email protected]
npm error node_modules/react-beautiful-dnd
npm error react-beautiful-dnd@"^13.1.1" from the root project
npm error
npm error Conflicting peer dependency: [email protected]
npm error node_modules/react
npm error peer react@"^16.8.5 || ^17.0.0 || ^18.0.0" from [email protected]
npm error node_modules/react-beautiful-dnd
npm error react-beautiful-dnd@"^13.1.1" from the root project
Why it happens: peer dependencies
A regular dependency is code a package brings along. A peer dependency, declared under peerDependencies, says something else: "I don't ship my own copy of this. I plug into the one your project uses, and it has to be in this range." Plugins and UI libraries use peers for the host they extend. A React component library declares react, an ESLint plugin declares eslint, an Angular library declares @angular/core. An app needs exactly one React, so a library that brought its own private copy would break that rule.npm 3 to 6 did not install peers. It printed a warning when the version was wrong, and plenty of projects carried those warnings for years. Since npm 7 (October 2020), peers are installed automatically and npm tries to build a tree that satisfies every peer range. When the clash involves your own package.json, which the report calls "the root project", no valid tree exists and npm stops with ERESOLVE. Deeper in the tree npm is more lenient: it settles the conflict using the nearest regular dependency and prints "npm warn ERESOLVE overriding peer dependency" instead of failing. Setting strict-peer-deps=true turns those warnings into errors as well.
Peer ranges are written in semver. We checked these results with the semver library that npm itself uses:
| Range | Accepts | Rejects (example) |
|---|---|---|
| ^1.2.3 | 1.2.3 up to, not including, 2.0.0 | 2.0.0 |
| ~1.2.3 | 1.2.3 up to, not including, 1.3.0 | 1.3.0 |
| ^0.2.3 | 0.2.3 up to, not including, 0.3.0 | 0.3.0 |
| ^16.8.0 || ^17.0.0 | 16.8 and later 16.x, any 17.x | 18.0.0 |
| >=4.8.4 <6.1.0 | 4.8.4 through 6.0.x | 7.0.2 |
| ^18.0.0 || ^19.0.0 | stable 18.x and 19.x | 19.0.0-rc.1, canary builds |
The last row catches people out. A prerelease (rc, beta, canary) does not satisfy an ordinary range even when the major version matches, so a project pinned to a React canary gets ERESOLVE even from libraries that support React 19. You can try ranges in the npm semver calculator.
Reading the report: a worked example
Read the report from the top. Each block answers one question:- While resolving: whose dependencies was npm placing? [email protected] is the name and version in your own package.json. In the second form it is the package whose peer could not be placed.
- Found: what is already in the tree ([email protected]) and who asked for it. "from the root project" means your package.json, and a leading "dev" marks a devDependency.
- Could not resolve dependency: the requirement that can't be met. [email protected] accepts React 16.8.5 and later 16.x, 17 or 18.
- Conflicting peer dependency (second form only): the version npm would have to add to satisfy that range. Here it is [email protected], the newest release that fits.
In one sentence: your project wants React 19, and react-beautiful-dnd 13.1.1 stops at React 18. Confirm it and look for a way out with read-only commands:
Bash:
# which peers does the package declare, and is it deprecated?
npm view react-beautiful-dnd peerDependencies
npm view react-beautiful-dnd deprecated
# peer range across releases: find the first version that accepts your major
npm view "@hello-pangea/dnd@>=16" peerDependencies.react
# why is a package installed, and through which chain? (needs node_modules)
npm explain react
# the whole tree; peers outside their range are marked "invalid"
npm ls react --all
The second command returned Atlassian's notice: react-beautiful-dnd is deprecated, and its GitHub repository has since been archived. The range query showed that @hello-pangea/dnd, a community-maintained fork, accepts "^18.0.0 || ^19.0.0" from version 18.0.0 onward. That is the real fix, not a flag.
The same pattern turns up across the ecosystem. These conflicts were live on the npm registry in October 2026. Peer ranges change with every release, so check again with npm view before acting:
| Your project | Package and its peer range | Practical fix |
|---|---|---|
| React 19 | react-beautiful-dnd 13.1.1: react ^16.8.5 || ^17 || ^18 (deprecated) | @hello-pangea/dnd 18.x, dnd-kit or Pragmatic drag and drop |
| React 18 or 19 | @testing-library/react-hooks 8.0.1: react ^16.9.0 || ^17.0.0 | renderHook from @testing-library/react 13.1 or later |
| ESLint 10 | eslint-plugin-react 7.37.5: eslint up to ^9.7 | Stay on ESLint 9 until the plugin declares 10 |
| TypeScript 7 | typescript-eslint 8.72.1: typescript >=4.8.4 <6.1.0 | Stay on TypeScript 6.0.x for now |
| Angular 22 with TypeScript 7 | @angular/compiler-cli 22.2.3: typescript >=6.0 <6.1 | The TypeScript version Angular supports; upgrade with ng update |
The ESLint row is more than a version rule. When we skipped the peer check and installed eslint-plugin-react 7.37.5 next to ESLint 10.13, the install completed, but in a config that detects the React version automatically (version: "detect"), linting crashed with "TypeError: Error while loading rule 'react/display-name': contextOrFilename.getFilename is not a function". The plugin still calls context.getFilename(), which ESLint 10 removed. It shows why silencing ERESOLVE is not the same as fixing the conflict.
React sits behind many of these conflicts because almost every component library declares it as a peer. Our React 2026 production notes cover the wider upgrade picture.
Fixes, in order of preference
| Situation | Fix | Risk |
|---|---|---|
| A newer release of the package already accepts your version | 1. Upgrade that package | Low |
| You upgraded a host (ESLint, TypeScript, React) before its plugins caught up | 2. Align your versions | Low |
| The package is deprecated, archived or idle for years | 3. Replace it | Migration work |
| One package's peer range is merely out of date and your tests pass | 4. overrides (npm 8.3+) or packageExtensions (npm 12+) | Medium, but visible and scoped |
| Many stale peer ranges and you have to ship today | 5. legacy-peer-deps in a committed .npmrc | High: switches off every peer check |
| Nothing else is possible | 6. --force | Highest |
1. Upgrade the package that declares the old peer
Check the latest release first with npm view @testing-library/react peerDependencies. Version 12.1.5 declares react <18.0.0, so it fails in a React 18 project, while 16.1.0 and later accept ^18.0.0 || ^19.0.0. This kind of upgrade is usually a major version jump, so read the changelog or migration guide. Current 16.x releases also list @testing-library/dom ^10 as a peer; add it to devDependencies explicitly:
Bash:
npm install -D @testing-library/react@latest @testing-library/dom@latest
2. Align your own versions
If you have just moved a host to a new major, the cheapest fix is often to step back until its plugins catch up:
Bash:
npm install -D eslint@9 # until eslint-plugin-react declares ESLint 10
npm install -D typescript@~6.0 # until typescript-eslint accepts TypeScript 7
Upgrade families together: react, react-dom, @types/react and @types/react-dom move as one unit. Angular packages pin each other exactly (@angular/core 22.2.3 asks for @angular/compiler 22.2.3), and the compiler accepts only TypeScript >=6.0 <6.1, so run ng update @angular/core @angular/cli rather than bumping single packages.
3. Replace an abandoned package
Don't wait for a deprecated, archived or long-idle package to widen its peer range. The last release of @testing-library/react-hooks, 8.0.1 from June 2022, still declares React ^16.9.0 || ^17.0.0, and its README points React 18+ users to the renderHook that ships with @testing-library/react 13.1 and later. For synchronous tests the switch is mostly an import change. The new renderHook returns only result, rerender and unmount, though: waitForNextUpdate, waitForValueToChange and result.all are gone, so tests that rely on them need rewriting with waitFor from @testing-library/react. For react-beautiful-dnd, Atlassian's deprecation notice lists the options: move to one of its forks (@hello-pangea/dnd, for example), switch to a similar library such as dnd-kit, or adopt Atlassian's own Pragmatic drag and drop.4. Override one dependency, on purpose
When one package's peer range is merely out of date and your tests pass with the newer host, say so in package.json. The overrides field works from npm 8.3.0 onward, and only in the root package.json:
Code:
{
"dependencies": {
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-beautiful-dnd": "^13.1.1"
},
"overrides": {
"react-beautiful-dnd": {
"react": "$react",
"react-dom": "$react-dom"
}
}
}
"$react" means "the same spec as my direct dependency react". You cannot give a different literal version for something you depend on directly: npm stops with EOVERRIDE ("Override for react@^19.2.0 conflicts with direct dependency"), and the $ reference is the documented way round it. Nesting the rule under react-beautiful-dnd limits it to that package and its own dependencies. After npm install, npm ls react --all marks the affected packages "overridden" instead of "invalid". An override silences the version check; it does not make old code compatible. Run your tests, explain the override in the pull request and remove it once upstream catches up. The react-beautiful-dnd example does not actually meet that bar: it supplies Droppable's defaults (type, direction, mode) through defaultProps on a memo-wrapped function component, and React 19 dropped defaultProps support for function components. The override gets the install through, but for this package the right move is the migration in step 3; we use it here only to show the syntax.
npm 12 (July 2026) adds packageExtensions, which repairs a dependency's manifest before resolution: you can add a missing dependency or replace a range in its peerDependencies. The repair is recorded in package-lock.json and shows up in npm ls and npm explain. In this example, old-eslint-plugin is a placeholder name:
Code:
{
"packageExtensions": {
"old-eslint-plugin@2": {
"peerDependencies": { "eslint": "^9.0.0 || ^10.0.0" }
}
}
}
Don't use it for eslint-plugin-react 7.37.5: as shown above, the install succeeds and linting then crashes on ESLint 10. Like overrides, packageExtensions is honored only in the root package.json, and npm refuses to publish a non-private package that contains it. Both fields are documented in the package.json reference.
5. --legacy-peer-deps, as a team decision
This flag makes npm ignore peerDependencies completely while building the tree, as npm 3 to 6 did. It doesn't install missing peers, it applies to every package rather than just the broken one, and npm's own documentation does not recommend it. If you use it, everyone has to: a lockfile created with it fails with "ERESOLVE could not resolve" as soon as someone runs npm install or npm ci without it. Store the setting in the project:
Bash:
npm config set legacy-peer-deps=true --location=project
cat .npmrc
# legacy-peer-deps=true
git add .npmrc package-lock.json
The conflicts don't go away; they are only hidden. npm ls --all still lists them as invalid and exits with ELSPROBLEMS. Watch the spelling, too. npm 10 silently ignores an unknown flag such as --legacy-peers-deps, so you see the same error and conclude the flag doesn't work. Newer npm 11 releases warn about unknown flags, and npm 12 rejects them.
6. --force, the last resort
--force keeps peer resolution running but lets conflicting peers into the root project. You get "npm warn ERESOLVE overriding peer dependency" blocks and a lockfile with a peer outside its declared range. The same flag switches off other protections as well: it ignores engines checks and lets npm audit fix install semver-major changes. The npm documentation is blunt: if you don't have a clear idea of what you want to do, don't use it. Nothing in package.json records the decision, so the next plain install fails again.7. A clean reinstall, done deliberately
A clean reinstall won't fix a real conflict. It does help when node_modules or the lockfile has gone stale, for example after switching branches, an interrupted install or a badly merged package-lock.json:
Bash:
rm -rf node_modules
npm install # rebuild from the existing lockfile
npm ls --all # anything still invalid or missing?
# only if you decide to re-resolve everything:
git switch -c chore/regenerate-lockfile
rm -rf node_modules package-lock.json
npm install
git diff --stat package-lock.json
Deleting the lockfile together with node_modules moves every dependency to the newest version its range allows, so do it on a branch and run the whole test suite. Deleting only package-lock.json is not enough: in our test npm kept the older version it found in node_modules and installed the newest release in range only after both were removed. Clearing the cache (npm cache clean --force) doesn't change how peers resolve; npm cache verify is enough if you suspect a damaged cache.
CI and Docker
In pipelines, use npm ci. It requires package-lock.json, deletes node_modules before installing, never writes to package.json or the lockfile, and stops with EUSAGE when the two disagree, listing lines such as "Missing: [email protected] from lock file". If your laptop installs fine but CI fails with ERESOLVE, check these:- The lockfile was generated with --legacy-peer-deps or --force on someone's machine, and CI runs without the flag. The npm ci documentation says you must pass the same flags; a committed .npmrc does that for you.
- Docker: if the Dockerfile copies only package.json and package-lock.json, .npmrc is missing from the image when npm ci runs. Copy it as well. Keep registry tokens out of the project .npmrc and pass them as build secrets or environment variables.
- Different npm majors don't always resolve peers identically. Node.js 22 bundles npm 10.9, Node.js 24 and 26 bundle npm 11, and npm 12 is installed separately and needs Node.js ^22.22.2, ^24.15.0 or 26 and later. Pin Node.
YAML:
# .github/workflows/ci.yml (excerpt)
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
cache: npm
- run: npm ci
- run: npm ls --all # once the tree is clean, catches hidden conflicts
- run: npm test
Code:
# Dockerfile (excerpt)
FROM node:24-slim
WORKDIR /app
# drop .npmrc from the next line if the project has none
COPY package.json package-lock.json .npmrc ./
RUN npm ci
COPY . .
Add the npm ls --all step once your tree is clean. In our test, plain npm ls exited with 0 despite hidden peer conflicts, npm ls --all returned 1, and a deliberate override passed. To pin versions:
- Put the major version in .nvmrc (for example 24). nvm, fnm and the node-version-file input of setup-node read it. Node.js 24 is an LTS line, and Node.js 26 becomes LTS on 28 October 2026.
- engines in package.json ("node": ">=24") on its own only produces an EBADENGINE warning; engine-strict=true in .npmrc turns it into an error.
- devEngines (npm 10.9+) checks the runtime and package manager before install, ci and run, and fails with EBADDEVENGINES on a mismatch.
- For Yarn or pnpm, pin the version with the packageManager field in package.json, which Corepack reads. Corepack ships with Node.js 14.19 through 24.x; on Node.js 25 and later, install it with npm install -g corepack.
Yarn and pnpm equivalents
Neither stops on a peer mismatch by default. Both warn and carry on, so the same problem arrives as a warning that is easy to miss.- Yarn (1.x and 4.x): pin a version with the resolutions field in the root package.json. Yarn 4 reports an incompatible peer as YN0060 INCOMPATIBLE_PEER_DEPENDENCY, which, in Yarn's words, does not prevent resolution but may leave the system in an incorrect state. For details, pass the p-prefixed code from the warning to yarn explain peer-requirements. packageExtensions in .yarnrc.yml is meant for adding missing dependencies; to rewrite existing ones, Yarn recommends resolutions.
- pnpm: warns by default, and strictPeerDependencies: true makes those warnings fatal. From pnpm 11 on, these settings belong in pnpm-workspace.yaml; the "pnpm" field in package.json, which pnpm 10 and older also accepted, is no longer read. pnpm's overrides also apply to peer dependencies. In the example below, old-ui-kit and old-eslint-plugin are placeholder names.
YAML:
# pnpm-workspace.yaml (pnpm 11 and later)
strictPeerDependencies: false # the default; true turns peer warnings into errors
peerDependencyRules:
allowedVersions:
"old-ui-kit>react": "19" # only silences the warning
overrides:
"old-eslint-plugin>eslint": "^10.0.0" # rewrites the peer range
Prevention
- Run npm outdated regularly. The Wanted and Latest columns show which major upgrades are waiting.
- Before moving a host (React, ESLint, TypeScript, Angular) to a new major, check its plugins' peer ranges with npm view.
- Upgrade families in one pull request: react + react-dom + @types/react + @types/react-dom; eslint + its plugins + typescript-eslint; Angular through ng update.
- Keep prereleases (rc, canary) out of applications unless you are ready to handle the peer conflicts they cause.
- Have your update bot open those families as groups. Examples for Dependabot (.github/dependabot.yml) and Renovate (renovate.json):
YAML:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
groups:
react:
patterns: ["react", "react-dom", "@types/react", "@types/react-dom"]
eslint:
patterns: ["eslint", "eslint-*", "@eslint/*", "typescript-eslint"]
Code:
{
"extends": ["config:recommended"],
"packageRules": [
{
"matchPackageNames": ["react", "react-dom", "@types/react", "@types/react-dom"],
"groupName": "react"
}
]
}
Related npm errors
| Code | Typical message | What to do |
|---|---|---|
| ETARGET | No matching version found for react@99. | The version or tag doesn't exist: a typo, an unpublished version, or a private registry that doesn't carry the package. Check with npm view PACKAGE versions. |
| EACCES | permission denied, usually when npm install -g writes to a system folder such as /usr/local/lib/node_modules | Don't use sudo. Install Node with a version manager such as nvm or fnm, or move npm's global prefix to a folder you own; npm has an official guide. |
| ENOENT | Could not read package.json (from commands such as npm run, npm start or npm test) | You're in the wrong folder or the project was never initialized: cd into the folder that holds package.json, or run npm init. |
| EBADENGINE, EBADDEVENGINES | Unsupported engine; Invalid engine "runtime" | Your Node or npm version is outside the range the project or a package declares; switch with your version manager. |
| EUSAGE (npm ci) | package.json and package-lock.json are not in sync; Missing: … from lock file | Run npm install locally and commit the updated lockfile. |
| EOVERRIDE | Override for react@^19.2.0 conflicts with direct dependency | Use the $ reference ("react": "$react") or the identical spec. |
FAQ
Is --legacy-peer-deps safe?It won't break the install itself, but because it turns off peer checks for the whole tree, a real incompatibility may only show up at runtime. Treat it as a temporary bridge, share it through .npmrc and track what is left with npm ls --all.
--force or --legacy-peer-deps?
Neither is a permanent fix. If you must pick one, --legacy-peer-deps is more predictable: it does one thing and can be recorded in .npmrc. --force removes other safeguards at the same time.
Should I delete package-lock.json?
Not as a reflex. It doesn't solve a real peer conflict, and it re-resolves every dependency. If you need to, do it on a branch and review the diff.
Why does it work on my machine but fail in CI or Docker?
Usually a flag used locally never made it to CI, .npmrc wasn't copied into the image, or the npm versions differ. Put the setting in .npmrc, copy the file into the image and pin the Node version.
Will clearing the npm cache help?
Not for ERESOLVE. The error comes from the logic of version ranges, and cached files don't change the outcome.