Skip to content

Lỗi thường gặp ⚠️

Lỗi là bạn của bạn. Chúng đang cố nói cho bạn điều gì đó. Hãy lắng nghe.

Tip 1: Reading Stack Traces

Problem

Bức tường chữ đỏ xuất hiện, bạn panic và không biết đọc từ đâu.

Solution

Đọc từ dưới lên: Framework code ở trên, YOUR code ở dưới.

Example

TypeError: Cannot read property 'name' of undefined
    at Object.get (node_modules/express/lib/request.js:345)
    at Layer.handle (node_modules/express/lib/router/layer.js:95)
    at trim_prefix (node_modules/express/lib/router/index.js:317)
    at Router.handle (node_modules/express/lib/router/index.js:284)
    at Function.handle (node_modules/express/lib/application.js:644)
    at getUserProfile (src/controllers/user.js:23)  ← START HERE!
    at processRequest (src/middleware/auth.js:45)

Reading Strategy:

  1. Đọc error type: TypeError
  2. Đọc message: Cannot read property 'name' of undefined
  3. Scroll xuống tìm YOUR code: src/controllers/user.js:23
  4. Mở file đó, line 23
  5. Fix: Variable nào là undefined?

Pro Tips

  • Framework/library code (node_modules): Bỏ qua
  • YOUR code: Focus vào đây
  • Multiple YOUR files: Start từ file đầu tiên
  • Line numbers: Exact location

Tip 2: "Works on My Machine"

Problem

Code chạy được trên laptop bạn, nhưng fail trên production hoặc laptop đồng nghiệp.

Solution

Environment differences: Node version, OS, environment variables, database state.

Example

javascript
// Bad: Hardcoded paths (Windows vs Linux)
const filePath = 'C:\\Users\\me\\data.json';  // ❌ Chỉ chạy trên Windows

// Good: Cross-platform paths
const path = require('path');
const filePath = path.join(__dirname, 'data.json');  // ✅ Chạy mọi nơi

// Bad: Missing environment variables
const apiKey = 'hardcoded-key';  // ❌ Không secure, không flexible

// Good: Environment variables
const apiKey = process.env.API_KEY;  // ✅ Config per environment
if (!apiKey) {
  throw new Error('API_KEY environment variable is required');
}

Pro Tips

  • Dockerize: Ship environment, không chỉ code
  • Environment variables: Dùng .env files
  • Version lock: package-lock.json, yarn.lock
  • Document dependencies: README với setup instructions

Tip 3: Null/Undefined Errors

Problem

Cannot read property 'x' of undefined - lỗi phổ biến nhất trong JavaScript.

Solution

Defensive programming: Validate inputs, use optional chaining.

Example

javascript
// Bad: Assume data exists
function displayUser(user) {
  return user.profile.name;  // ❌ Crashes if user or profile is null
}

// Good: Optional chaining (ES2020+)
function displayUser(user) {
  return user?.profile?.name ?? 'Unknown';  // ✅ Safe
}

// Good: Explicit validation
function displayUser(user) {
  if (!user || !user.profile) {
    return 'Unknown';
  }
  return user.profile.name;
}

// Good: TypeScript
function displayUser(user: User | null): string {
  return user?.profile?.name ?? 'Unknown';
}

Pro Tips

  • Optional chaining: obj?.prop?.nested
  • Nullish coalescing: value ?? defaultValue
  • TypeScript: Catch at compile time
  • Validate at boundaries: API responses, user inputs

Tip 4: Async/Await Errors

Problem

Async code không chạy đúng thứ tự, hoặc errors không được catch.

Solution

Always await promises, wrap trong try-catch.

Example

javascript
// Bad: Forgot await
async function getUser(id) {
  const user = fetchUser(id);  // ❌ Returns Promise, not user
  console.log(user.name);      // ❌ undefined
}

// Good: Await promise
async function getUser(id) {
  const user = await fetchUser(id);  // ✅ Wait for result
  console.log(user.name);
}

// Bad: No error handling
async function getUser(id) {
  const user = await fetchUser(id);  // ❌ If fails, crashes app
  return user;
}

// Good: Try-catch
async function getUser(id) {
  try {
    const user = await fetchUser(id);
    return user;
  } catch (error) {
    console.error('Failed to fetch user:', error);
    throw new Error(`User ${id} not found`);
  }
}

Pro Tips

  • ESLint rule: no-floating-promises
  • Always return from async functions
  • Parallel requests: Promise.all([req1, req2])
  • Sequential: await each one

Tip 5: Off-by-One Errors

Problem

Loop chạy quá ít hoặc quá nhiều lần, array index out of bounds.

Solution

Careful với boundary conditions: < vs <=, 0 vs 1 indexed.

Example

javascript
// Bad: Off-by-one
const arr = [1, 2, 3, 4, 5];
for (let i = 1; i <= arr.length; i++) {  // ❌ Starts at 1, goes to 6
  console.log(arr[i]);  // Misses first, undefined at end
}

// Good: Correct boundaries
for (let i = 0; i < arr.length; i++) {  // ✅ 0 to 4
  console.log(arr[i]);
}

// Better: Use array methods
arr.forEach(item => console.log(item));

// Bad: Slice off-by-one
const last3 = arr.slice(-4);  // ❌ Gets 4 items, not 3

// Good: Correct slice
const last3 = arr.slice(-3);  // ✅ Gets last 3 items

Pro Tips

  • Test boundary conditions: Empty array, single item, full array
  • Use array methods: forEach, map, filter (no index management)
  • Inclusive vs exclusive: [start, end) in most languages

Tip 6: Type Coercion Bugs

Problem

JavaScript type coercion gây ra unexpected behavior.

Solution

Use strict equality (===), explicit type conversion.

Example

javascript
// Bad: Loose equality
if (user.age == '18') {  // ❌ True for both 18 and '18'
  console.log('Adult');
}

// Good: Strict equality
if (user.age === 18) {  // ✅ Only true for number 18
  console.log('Adult');
}

// Bad: Truthy/falsy confusion
if (user.count) {  // ❌ False for 0, but 0 is valid count
  console.log('Has items');
}

// Good: Explicit check
if (user.count > 0) {  // ✅ Clear intent
  console.log('Has items');
}

// Bad: String concatenation
const total = '10' + 5;  // ❌ '105' (string)

// Good: Explicit conversion
const total = Number('10') + 5;  // ✅ 15 (number)

Pro Tips

  • Always use === and !==
  • ESLint rule: eqeqeq
  • TypeScript: Catch type errors at compile time
  • Be explicit: Number(), String(), Boolean()

Tip 7: Mutation Bugs

Problem

Accidentally mutating objects/arrays gây side effects không mong muốn.

Solution

Immutable updates: Tạo copy thay vì mutate original.

Example

javascript
// Bad: Mutate original
function addItem(cart, item) {
  cart.items.push(item);  // ❌ Mutates original cart
  return cart;
}

// Good: Immutable update
function addItem(cart, item) {
  return {
    ...cart,
    items: [...cart.items, item]  // ✅ New array
  };
}

// Bad: Shallow copy trap
const user = { name: 'John', address: { city: 'NYC' } };
const copy = { ...user };
copy.address.city = 'LA';  // ❌ Mutates original user.address!

// Good: Deep copy
const copy = JSON.parse(JSON.stringify(user));  // ✅ True deep copy
// Or use lodash: _.cloneDeep(user)

Pro Tips

  • Spread operator: [...arr], {...obj} (shallow copy)
  • Array methods: map, filter, slice (return new array)
  • Avoid: push, pop, splice, sort (mutate original)
  • Immutable libraries: Immer, Immutable.js

Tip 8: Race Conditions

Problem

Multiple async operations chạy đồng thời, kết quả phụ thuộc vào timing.

Solution

Serialize operations hoặc use proper synchronization.

Example

javascript
// Bad: Race condition
let counter = 0;
async function increment() {
  const current = counter;
  await delay(100);  // Simulate async work
  counter = current + 1;  // ❌ Lost updates if called concurrently
}

// Good: Atomic operation
let counter = 0;
async function increment() {
  counter++;  // ✅ Atomic (but still not thread-safe in multi-threaded)
}

// Bad: Stale closure
for (const i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 100);  // ❌ Prints 5, 5, 5, 5, 5
}

// Good: Block scope
for (let i = 0; i < 5; i++) {
  setTimeout(() => console.log(i), 100);  // ✅ Prints 0, 1, 2, 3, 4
}

Pro Tips

  • Use let instead of var
  • Locks/mutexes for critical sections
  • Queue async operations: p-queue library
  • Test with concurrent requests

Tip 9: Memory Leaks

Problem

Application memory usage tăng dần, eventually crashes.

Solution

Clean up: Remove event listeners, clear timers, close connections.

Example

javascript
// Bad: Memory leak
function setupListener() {
  const button = document.getElementById('btn');
  button.addEventListener('click', handleClick);  // ❌ Never removed
}

// Good: Cleanup
function setupListener() {
  const button = document.getElementById('btn');
  const handler = () => handleClick();
  button.addEventListener('click', handler);
  
  // Cleanup function
  return () => button.removeEventListener('click', handler);
}

// Bad: Timer leak
function startPolling() {
  setInterval(() => fetchData(), 1000);  // ❌ Never cleared
}

// Good: Clear timer
function startPolling() {
  const intervalId = setInterval(() => fetchData(), 1000);
  
  // Cleanup function
  return () => clearInterval(intervalId);
}

// React example
useEffect(() => {
  const cleanup = setupListener();
  return cleanup;  // ✅ Cleanup on unmount
}, []);

Pro Tips

  • Browser DevTools: Memory profiler
  • Node.js: --inspect flag, Chrome DevTools
  • Common causes: Event listeners, timers, closures, global variables
  • Test: Run app for extended period, monitor memory

Tip 10: CORS Errors

Problem

Access to fetch at 'https://api.example.com' from origin 'http://localhost:3000' has been blocked by CORS policy

Solution

Configure CORS headers on server, or use proxy in development.

Example

javascript
// Backend: Enable CORS (Express)
const cors = require('cors');
app.use(cors({
  origin: 'http://localhost:3000',  // Allow specific origin
  credentials: true  // Allow cookies
}));

// Or allow all (development only!)
app.use(cors());

// Frontend: Include credentials
fetch('https://api.example.com/data', {
  credentials: 'include'  // Send cookies
});

// Development proxy (package.json)
{
  "proxy": "http://localhost:5000"
}

// Now fetch from relative URL
fetch('/api/data');  // Proxied to http://localhost:5000/api/data

Pro Tips

  • CORS is browser security, not server security
  • Production: Whitelist specific origins
  • Development: Use proxy to avoid CORS
  • Preflight requests: OPTIONS method for complex requests

📋 Quick Reference

ErrorCommon CauseQuick Fix
Stack TraceFramework codeRead from bottom up
Works on My MachineEnvironment differencesDocker, env vars
Null/UndefinedMissing validationOptional chaining ?.
Async ErrorsForgot awaitAdd await, try-catch
Off-by-OneWrong boundariesTest edge cases
Type CoercionLoose equalityUse ===
MutationMutating objectsImmutable updates
Race ConditionsConcurrent asyncSerialize operations
Memory LeaksNo cleanupRemove listeners, clear timers
CORSMissing headersEnable CORS on server

🎯 Luyện tập ngay