Error Cannot find module 'ajv/dist/compile/codegen' adalah salah satu error yang cukup menjengkelkan dalam ekosistem React dan Node.js. Error ini sering muncul secara tiba-tiba—terutama setelah proses instalasi dependensi atau pembaruan paket—dan membuat aplikasi yang sebelumnya berjalan normal menjadi tidak bisa dijalankan sama sekali. Dalam artikel ini, kita akan membahas tuntas apa yang sebenarnya terjadi, akar masalahnya, cara memperbaikinya secara permanen, hingga langkah pencegahan agar error ini tidak kembali muncul di masa depan.


Apa yang Sebenarnya Dikeluhkan Error Ini

Ketika error ini muncul, yang kamu lihat di terminal biasanya adalah pesan seperti berikut:

Error: Cannot find module 'ajv/dist/compile/codegen'
Require stack:
- /path/to/project/node_modules/ajv-keywords/dist/definitions/limit.js
- /path/to/project/node_modules/ajv-keywords/dist/index.js
- /path/to/project/node_modules/schema-utils/dist/validate.js
- ...

Atau variasi yang lebih singkat:

Module not found: Error: Can't resolve 'ajv/dist/compile/codegen' in '/path/to/project/node_modules/ajv-keywords/dist/definitions'

Pesan error ini, meskipun terlihat teknis, sesungguhnya memiliki arti yang cukup sederhana. Dalam bahasa Indonesia: sistem tidak bisa menemukan modul ajv/dist/compile/codegen yang dibutuhkan oleh paket lain (biasanya ajv-keywords) untuk bisa berjalan. Ini adalah error resolusi modul—Node.js atau bundler (seperti webpack) mencoba memuat sebuah file dari paket ajv, tetapi file tersebut tidak ada di lokasi yang diharapkan.

Paket ajv sendiri adalah Another JSON Validator, sebuah library validasi JSON schema yang sangat cepat dan banyak digunakan di ekosistem JavaScript. Paket ajv-keywords adalah paket tambahan yang menyediakan custom keywords untuk AJV, dan paket ini mengimpor file dari path ajv/dist/compile/codegen secara langsung. Ketika struktur folder ajv berubah antar versi—misalnya file codegen dipindahkan, di-rename, atau dihapus—maka impor yang dilakukan oleh ajv-keywords menjadi rusak dan error inilah yang muncul.

Kenapa error ini sering muncul secara tiba-tiba? Jawabannya ada di mekanisme resolusi dependensi npm dan yarn. Ketika kamu menjalankan npm install atau yarn install, package manager menyelesaikan pohon dependensi dan bisa saja memasang versi ajv yang tidak kompatibel dengan versi ajv-keywords yang juga terpasang. Ini terutama terjadi ketika ada paket-paket berbeda dalam pohon dependensi yang masing-masing membutuhkan versi ajv yang berbeda, dan npm menyelesaikannya dengan memasang dua versi ajv secara bersamaan—atau justru menimpa satu dengan yang lain.

Perhatikan contoh skenario berikut. Kamu memiliki package.json seperti ini:

{
  "dependencies": {
    "react": "^18.2.0",
    "webpack": "^5.75.0",
    "schema-utils": "^3.3.0"
  }
}

Ketika kamu menjalankan:

npm install

Npm akan memasang schema-utils, yang bergantung pada ajv-keywords, yang pada gilirannya bergantung pada ajv. Jika ada paket lain (misalnya webpack atau dependensi dari webpack) yang juga bergantung pada ajv tetapi versi yang berbeda, resolusi bisa berujung pada ketidakcocokan. File codegen.js yang diharapkan ada di ajv/dist/compile/ ternyata tidak ada karena versi ajv yang terpasang memiliki struktur folder yang berbeda.

Error ini juga bisa muncul setelah kamu menghapus node_modules dan menginstal ulang, setelah berpindah branch di git, setelah upgrade Node.js, atau setelah menambahkan paket baru yang secara transitif membawa versi ajv yang tidak kompatibel. Intinya, setiap kali pohon dependensi direkonstruksi, ada potensi versi ajv yang terpasang tidak sesuai dengan ekspektasi ajv-keywords, dan error inilah konsekuensinya.


Akar Masalah yang Paling Sering

Setelah menangani error ini berkali-kali di berbagai proyek, berikut adalah root cause yang paling sering menjadi penyebab, diurutkan dari yang paling umum:

1. Versi ajv dan ajv-keywords yang tidak kompatibel. Ini adalah penyebab nomor satu. Paket ajv-keywords@3.x dirancang untuk bekerja dengan ajv@6.x, sementara ajv-keywords@5.x dirancang untuk ajv@8.x. Ketika ajv-keywords versi 3 terpasang tetapi ajv yang terpasang adalah versi 8 (atau sebaliknya), struktur folder berbeda secara drastis. Versi 6 ajv menyimpan file codegen di path yang berbeda dengan versi 8. Import path ajv/dist/compile/codegen hanya valid di ajv versi 8, jadi jika versi 6 yang terpasang, file tersebut memang tidak ada.

2. Duplicate versi ajv di node_modules. Karena npm secara default melakukan hoisting (menaikkan paket ke akar node_modules), dua paket yang membutuhkan versi ajv berbeda bisa berkonflik. Misalnya, schema-utils@3 membutuhkan ajv@6, tetapi paket lain di pohon dependensi membutuhkan ajv@8. npm mungkin hanya memasang satu versi di root node_modules, dan versi yang kalah tidak bisa menemukan file yang dibutuhkan.

3. Cache npm atau yarn yang korup. Terkadang, cache package manager menyimpan snapshot versi yang sudah outdated atau korup. Ketika instalasi dilakukan, npm mengambil dari cache yang tidak merepresentasikan kondisi terbaru dari registry, menghasilkan pohon dependensi yang inkonsisten.

4. File package-lock.json atau yarn.lock yang tidak sinkron. Lock file yang sudah outdated—misalnya sudah di-commit ke git beberapa minggu lalu dan tidak diperbarui setelah perubahan dependensi—bisa menyebabkan resolusi yang berbeda saat npm install dijalankan di mesin yang berbeda atau setelah cache dibersihkan.

5. Penggunaan npm ci dengan lock file yang konflik. Perintah npm ci sangat ketat dan akan gagal jika ada inkonsistensi antara package.json dan package-lock.json. Namun dalam beberapa kasus, perintah ini justru memasang kombinasi yang memicu error ini karena paksa mengikuti lock file yang sudah tidak kompatibel.

Cara memastikan penyebab mana yang kamu alami:

  • Jalankan npm ls ajv (atau yarn why ajv) untuk melihat semua versi ajv yang terpasang dan siapa yang membutuhkannya. Jika ada lebih dari satu versi, penyebabnya adalah duplikasi versi (root cause #1 atau #2).
  • Periksa apakah file ajv/dist/compile/codegen.js ada: ls node_modules/ajv/dist/compile/. Jika folder compile tidak ada atau kosong, kemungkinan versi ajv yang terpasang adalah versi 6 (root cause #1).
  • Bersihkan cache dan instal ulang. Jika error hilang, penyebabnya adalah cache korup (root cause #3).
  • Bandingkan hash di package-lock.json dengan yang di registry. Jika tidak cocok, lock file mungkin korup (root cause #4).

Cara Memperbaiki

Bagian ini membahas langkah-langkah perbaikan secara berurutan, dari yang paling cepat hingga yang paling menyeluruh. Ikuti langkah-langkah ini satu per satu sampai error teratasi.

Langkah 1: Hapus dan Instal Ulang Dependensi

Langkah paling sederhana yang sering kali langsung berhasil:

rm -rf node_modules
rm package-lock.json
npm install

Atau jika menggunakan yarn:

rm -rf node_modules
rm yarn.lock
yarn install

Output yang diharapkan: Proses instalasi selesai tanpa error, dan ketika kamu menjalankan npm start atau yarn start, aplikasi berjalan normal tanpa pesan Cannot find module.

Namun, jika langkah ini tidak berhasil, lanjut ke langkah berikutnya.

Langkah 2: Bersihkan Cache Package Manager

Cache yang korup bisa menyebabkan versi yang salah terpasang:

npm cache clean --force
rm -rf node_modules
rm package-lock.json
npm install

Untuk yarn:

yarn cache clean
rm -rf node_modules
rm yarn.lock
yarn install

Output yang diharapkan: Setelah instalasi ulang, jalankan npm ls ajv dan pastikan hanya ada satu versi ajv yang terpasang (idealnya versi 8.x).

Langkah 3: Pasang Versi ajv dan ajv-keywords yang Kompatibel Secara Eksplisit

Jika duplikasi versi adalah masalahnya, pasang versi yang kompatibel secara eksplisit di package.json:

npm install ajv@8 ajv-keywords@5 --save

Atau, jika paket-paketmu masih membutuhkan ajv@6:

npm install ajv@6 ajv-keywords@3 --save

Perintah ini memastikan versi yang tepat terpasang di root node_modules dan menjadi resolusi tunggal untuk seluruh pohon dependensi.

Output yang diharapkan: package.json sekarang memuat entri eksplisit untuk ajv dan ajv-keywords, dan npm ls ajv menunjukkan hanya satu versi.

Langkah 4: Gunakan overrides (npm) atau resolutions (yarn)

Jika ada paket transitif yang memaksa versi ajv tertentu, kamu bisa meng-override-nya:

Untuk npm (versi 8+), tambahkan di package.json:

{
  "overrides": {
    "ajv": "8.12.0",
    "ajv-keywords": "5.1.0"
  }
}

Untuk yarn, tambahkan:

{
  "resolutions": {
    "ajv": "8.12.0",
    "ajv-keywords": "5.1.0"
  }
}

Kemudian jalankan ulang instalasi:

rm -rf node_modules
npm install

Output yang diharapkan: Semua dependensi yang membutuhkan ajv akan menggunakan versi 8.12.0, menghilangkan duplikasi dan inkonsistensi.

Langkah 5: Perbaiki dengan npm dedupe

Kadang-kadang, npm memasang versi yang sama di beberapa lokasi dalam node_modules. Deduplication bisa membantu:

npm dedupe

Output yang diharapkan: npm merestrukturisasi node_modules sehingga paket-paket duplikat dijadikan satu.

Verifikasi Solusi Berhasil

Setelah menjalankan langkah perbaikan, verifikasi dengan urutan berikut:

# 1. Pastikan file yang dicari ada
ls node_modules/ajv/dist/compile/codegen.js

# 2. Pastikan hanya satu versi ajv
npm ls ajv

# 3. Jalankan aplikasi
npm start

Jika file codegen.js ada, hanya ada satu versi ajv, dan aplikasi berjalan tanpa error, maka masalah sudah teratasi secara permanen.


Mencegah Error Ini Kembali

Memperbaiki error saja tidak cukup jika tidak ada langkah pencegahan. Berikut strategi dan konfigurasi yang bisa mencegah error ini muncul kembali.

1. Selalu Commit Lock File

Lock file (package-lock.json, yarn.lock, atau pnpm-lock.yaml) adalah jaminan bahwa setiap orang dalam tim dan setiap environment (CI/CD, staging, production) mendapatkan versi dependensi yang persis sama. Jangan pernah menambahkannya ke .gitignore. Dengan lock file yang konsisten, resolusi dependensi menjadi deterministik dan kemungkinan inkonsistensi versi ajv berkurang drastis.

# Pastikan lock file di-commit
git add package-lock.json
git commit -m "chore: update lock file"

2. Gunakan overrides atau resolutions Secara Proaktif

Bahkan jika error belum muncul, menambahkan override untuk paket yang diketahui bermasalah adalah praktik defensif yang baik:

{
  "overrides": {
    "ajv": "^8.12.0",
    "ajv-keywords": "^5.1.0"
  }
}

Konfigurasi ini memaksa seluruh pohon dependensi menggunakan versi yang kompatibel, terlepas dari apa yang dideklarasikan oleh paket transitif.

3. Gunakan npm ci di CI/CD, Bukan npm install

Perintah npm ci menginstal dependensi strictly berdasarkan lock file tanpa memodifikasinya. Ini lebih deterministik dan menghindari "drift" versi:

# Contoh GitHub Actions
- name: Install dependencies
  run: npm ci

4. Best Practice: Audit Dependensi Secara Berkala

Jalankan npm audit secara berkala dan perbarui paket yang memiliki vulnerability atau inkonsistensi:

npm audit fix

Atau gunakan tools seperti npm-check-updates untuk memperbarui dependensi secara terkontrol:

npx npm-check-updates -u
npm install

5. Perbedaan Antar OS

Perlu diperhatikan bahwa ada nuansa perbedaan antar sistem operasi yang bisa mempengaruhi munculnya error ini:

  • Windows: Path di Windows menggunakan backslash (\), dan terkadang symlink di node_modules tidak bekerja dengan baik, terutama jika proyek berada di drive yang berbeda. Jika kamu mengalami error ini di Windows tetapi tidak di macOS/Linux, coba aktifkan Developer Mode di Windows 10/11 untuk mengizinkan symlink, atau gunakan npm install --no-optional untuk menghindari paket optional yang mungkin membawa versi ajv berbeda.
 # Di Windows, pastikan symlink diizinkan
 npm config set ignore-scripts false
 npm install
  • macOS/Linux: Case-sensitive filesystem di Linux bisa menyebabkan masalah jika ada paket yang mengimpor dengan case yang berbeda (misalnya Ajv vs ajv). Meskipun ini jarang terkait error spesifik ini, pastikan nama path persis sesuai.

  • WSL (Windows Subsystem for Linux): Performa filesystem di WSL, terutama jika node_modules berada di drive Windows (/mnt/c/), bisa sangat lambat dan terkadang menyebabkan instalasi korup. Solusi terbaik: simpan proyek di filesystem native WSL (~/projects/).

 # Di WSL, pindahkan proyek ke filesystem native
 cp -r /mnt/c/Users/nama/project ~/project
 cd ~/project
 npm install

6. Konfigurasi .npmrc untuk Stabilitas

Buat file .npmrc di root proyek dengan konfigurasi berikut untuk meningkatkan stabilitas resolusi dependensi:

# .npmrc
save-exact=true
package-lock=true
legacy-peer-deps=false

Opsi save-exact=true memastikan versi yang dipasang dicatat secara eksak (tanpa caret ^ atau tilde ~) di package.json, mengurangi potensi versi bergeser saat instalasi ulang.


Diagnosis Lebih Dalam

Jika semua solusi di atas sudah dicoba tetapi error masih persisten, saatnya melakukan diagnosis yang lebih mendalam.

1. Periksa Struktur node_modules Secara Manual

Kadang-kadang, hoisting yang dilakukan npm menyembunyikan masalah. Periksa apakah ada versi ajv yang bersarang di dalam subdirektori paket lain:

find node_modules -name "ajv" -type d

Output yang mungkin:

node_modules/ajv
node_modules/schema-utils/node_modules/ajv
node_modules/webpack/node_modules/ajv

Jika ada lebih dari satu direktori ajv, berarti ada duplikasi. Paket yang mengimpor ajv/dist/compile/codegen mungkin merujuk ke versi yang salah. Solusi: gunakan overrides atau resolutions seperti yang dibahas di langkah 4, atau pertimbangkan beralih ke pnpm yang mengelola dependensi secara lebih ketat dengan struktur content-addressable store.

2. Baca Log Instalasi dengan Verbose

Jalankan instalasi dengan flag verbose untuk melihat resolusi dependensi secara detail:

npm install --loglevel verbose

Atau untuk informasi yang lebih mendalam:

npm install --loglevel silly 2>&1 | tee install-log.txt

Cari baris yang menyebutkan ajv dalam log tersebut. Perhatikan versi mana yang direlokasikan (hoisted) dan mana yang ditempatkan di subdirektori. Log ini juga akan menunjukkan jika ada warning tentang peer dependency yang unmet—yang sering kali adalah petunjuk awal inkonsistensi versi.

3. Gunakan npm explain untuk Menguji Paket Bermasalah

Jika ajv-keywords yang bermasalah, jalankan:

npm explain ajv-keywords

Perintah ini akan menunjukkan mengapa versi tertentu dari ajv-keywords terpasang, paket mana yang memintanya, dan apakah ada conflict.

4. Periksa Apakah Ada Post-Install Script yang Korup

Beberapa paket menjalankan script postinstall yang bisa memodifikasi node_modules:

npm ls --long | grep postinstall

Jika ada paket dengan postinstall script yang mencurigakan, coba instal tanpa menjalankan script:

npm install --ignore-scripts

Kemudian jalankan script secara manual satu per satu untuk mengidentifikasi mana yang menyebabkan masalah.

5. Beralih ke Package Manager yang Lebih Ketat

Pnpm secara default menggunakan struktur symlink yang ketat di mana setiap paket hanya bisa mengakses dependensi yang eksplisit dideklarasikan. Ini mengeliminasi hampir seluruh masalah hoisting dan duplikasi:

# Instal pnpm
npm install -g pnpm

# Hapus node_modules dan lock file lama
rm -rf node_modules package-lock.json

# Instal dengan pnpm
pnpm install

Pnpm juga memiliki mekanisme pnpm.overrides di package.json yang bekerja mirip dengan resolutions di yarn:

{
  "pnpm": {
    "overrides": {
      "ajv": "8.12.0"
    }
  }
}

6. Sumber Resmi untuk Deep-Dive

Untuk pemahaman yang lebih mendalam tentang mekanisme resolusi modul dan masalah dependensi di ekosistem npm, berikut adalah sumber-sumber resmi yang direkomendasikan:

Sebagai catatan penutup, error Cannot find module 'ajv/dist/compile/codegen' pada dasarnya adalah gejala dari masalah yang lebih luas dalam manajemen dependensi JavaScript: ketidaksinkronan versi di pohon dependensi. Memahami mekanisme resolusi dependensi dan mengadopsi praktik pengelolaan dependensi yang disiplin—lock file yang konsisten, override yang proaktif, dan package manager yang ketat—bukan hanya akan memperbaiki error ini, tetapi juga mencegah kelas error serupa di masa depan. Dengan langkah-langkah yang telah dibahas di atas, kamu seharusnya kini memiliki pemahaman yang utuh tentang masalah ini dan peralatan yang cukup untuk mengatasinya secara permanen.