Cara Membaca Error Messages
Kemampuan membaca error message dengan benar adalah skill debugging paling fundamental. Error message memberitahu kamu apa yang salah, di mana, dan seringkali mengapa.
Anatomi Error Message
Uncaught TypeError: Cannot read properties of undefined (reading "name")
at UserProfile (UserProfile.jsx:15:23)
at renderWithHooks (react-dom.development.js:14985:18)
at mountIndeterminateComponent (react-dom.development.js:17811:13)
Komponen:
- Error type:
TypeError - Error message:
Cannot read properties of undefined (reading "name") - Stack trace: urutan function calls yang mengarah ke error
- Location:
UserProfile.jsx:15:23(file, baris, kolom)
Jenis Error Umum di JavaScript
TypeError
Operasi pada tipe data yang salah:
// Cannot read properties of undefined
const user = undefined;
console.log(user.name); // ❌ TypeError!
// Fix: cek dulu apakah user ada
console.log(user?.name); // ✅ undefined (tanpa error)
// ... is not a function
const angka = 42;
angka(); // ❌ TypeError: angka is not a function
// Fix: angka bukan function, jangan dipanggil
// Cannot set properties of null
document.getElementById("tidak-ada").textContent = "hi";
// Fix: cek dulu apakah element ada
const el = document.getElementById("tidak-ada");
if (el) el.textContent = "hi";
ReferenceError
Mengakses variabel yang belum dideklarasi:
console.log(namaUser); // ❌ ReferenceError: namaUser is not defined
// Fix: deklarasikan dulu
const namaUser = "Budi";
// Juga bisa terjadi karena scope
function outer() {
const x = 10;
}
console.log(x); // ❌ ReferenceError (x hanya ada di dalam outer)
SyntaxError
Kesalahan penulisan kode:
// Unexpected token
const obj = { name: "Budi", }; // Trailing comma OK di JS modern
JSON.parse("{ name: \"Budi\" }"); // ❌ SyntaxError: JSON membutuhkan key dalam quotes
// Unexpected end of input
function hello() {
console.log("hi");
// ❌ SyntaxError: kurung tutup lupa!
// Fix JSON:
JSON.parse('{"name": "Budi"}'); // ✅
RangeError
Nilai di luar range yang diizinkan:
const arr = new Array(-1); // ❌ RangeError: Invalid array length
// Fix: length harus positif
function recursive() {
recursive(); // ❌ RangeError: Maximum call stack size exceeded
}
// Fix: tambahkan base case untuk menghentikan recursion
Membaca Stack Trace
Stack trace dibaca dari atas ke bawah:
Error: Data tidak ditemukan
at fetchUser (api.js:25:11) ← error terjadi di sini
at loadProfile (profile.js:10:5) ← dipanggil dari sini
at handleClick (app.js:45:3) ← yang dipanggil dari sini
at HTMLButtonElement.onclick (index.html:12:1)
Baris paling atas adalah tempat error terjadi. Baris di bawahnya menunjukkan chain of calls yang mengarah ke sana. Biasanya kamu fokus pada baris yang ada di kode kamu (bukan di library).
Error di Async Code
Unhandled Promise Rejection: TypeError: Failed to fetch
at fetchData (api.js:5:18)
at async loadPage (page.js:12:20)
Untuk async error, pastikan kamu selalu menggunakan try/catch:
// ❌ Error tidak tertangkap
async function loadData() {
const response = await fetch("/api/data");
const data = await response.json();
}
// ✅ Error tertangkap dan ditangani
async function loadData() {
try {
const response = await fetch("/api/data");
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
return data;
} catch (error) {
console.error("Gagal load data:", error.message);
return null;
}
}
Tips Membaca Error
- Baca dari atas — error type dan message dulu
- Cari file kamu di stack trace — abaikan internal library
- Perhatikan baris dan kolom — langsung ke lokasi error
- Google error message — kemungkinan besar orang lain pernah mengalami
- Jangan panik melihat stack trace panjang — fokus pada baris teratas yang relevan
Reading Minified Stack Traces
Di production, kode di-minify (variable userName jadi a, function validateOrder jadi q). Stack trace jadi cryptic:
TypeError: Cannot read properties of undefined (reading "a")
at q (app.min.js:1:48291)
at r (app.min.js:1:49012)
at HTMLButtonElement.<anonymous> (app.min.js:1:51203)
Tanpa konteks, "function q baris 1 kolom 48291" tidak bisa didebug. Source maps adalah jawabannya — file .map berisi mapping dari posisi minified ke file source asli + baris + kolom sebelum minify.
Aktifkan Source Maps di DevTools
Chrome DevTools sudah otomatis baca source map kalau bundle-nya punya comment:
//# sourceMappingURL=app.min.js.map
Kalau belum aktif: Settings (ikon gear) → Sources → centang:
- Enable JavaScript source maps — untuk JS bundle
- Enable CSS source maps — untuk CSS (SCSS/PostCSS)
Setelah aktif, stack trace di console dan breakpoint di Sources akan menunjuk ke kode source asli, bukan minified.
Source Map Strategies di Production
Deploy .map public = siapa saja bisa download kode asli kamu. Ada beberapa strategi aman:
| Strategi | Cara | Kapan Dipakai |
|---|---|---|
source-map |
Map file publik | Open-source atau debugging terbuka |
hidden-source-map |
Generate .map, tapi tidak ada comment sourceMappingURL |
Production — upload map ke Sentry/Datadog, bukan public |
nosources-source-map |
Map ada tapi sourcesContent kosong |
Debug di DevTools tanpa kasih source code |
eval-source-map |
Inline ke bundle (slow, dev only) | Development mode |
Pattern umum untuk production:
# Build dengan hidden-source-map
webpack --devtool hidden-source-map
# Upload map ke Sentry saat release
sentry-cli releases files $VERSION upload-sourcemaps ./dist
# Hapus .map dari server sebelum deploy
rm dist/*.map
Sentry/Datadog/Rollbar akan otomatis resolve stack trace minified ke kode asli saat menampilkan error — cuma untuk internal, tidak bocor ke public.