Sửa lỗi 'Route.get() requires a callback function but got [object Undefined]' trong Express.js

beginner💚 Node.js2026-05-20| Node.js 14+, Express.js 4.x, mọi hệ điều hành (Linux/macOS/Windows)

Error Message

Error: Route.get() requires a callback function but got a [object Undefined]
#express#routing#middleware#undefined#nodejs

Lỗi Gặp Phải

Error: Route.get() requires a callback function but got a [object Undefined]

Server Express của bạn bị crash ngay khi khởi động — trước khi xử lý bất kỳ request nào. Stack trace chỉ thẳng vào lời gọi router.get(), app.get(), hoặc router.post() gây ra lỗi.

Nguyên Nhân

Express kiểm tra từng argument bạn truyền vào route. Nếu truyền bất cứ thứ gì không phải là function — kể cả undefined — nó sẽ throw lỗi ngay lập tức. Không có cơ chế phục hồi hay fallback nào cả.

Nguyên nhân gốc rễ hầu như luôn là một trong hai trường hợp:

  • Một biến bị resolve thành undefined do lỗi import hoặc require
  • Một function không tồn tại tại đường dẫn bạn đang import (sai tên named export)

Các Nguyên Nhân Phổ Biến Và Cách Sửa

1. Sai tên named export (thường gặp nhất)

Bạn export một function với tên này nhưng lại import với tên khác. Kết quả là biến đó âm thầm trở thành undefined — không có cảnh báo, chỉ crash khi khởi động.

// controllers/userController.js
const getUsers = (req, res) => res.json([]);
module.exports = { getUsers };

// routes/users.js — SAI
const { getAllUsers } = require('../controllers/userController'); // undefined!
router.get('/', getAllUsers); // 💥 crash

// routes/users.js — ĐÚNG
const { getUsers } = require('../controllers/userController');
router.get('/', getUsers);

Trước khi đăng ký route, hãy log ra giá trị bạn vừa import:

const { getUsers } = require('../controllers/userController');
console.log(typeof getUsers); // 'function' = ổn, 'undefined' = có vấn đề
router.get('/', getUsers);

2. Phụ thuộc vòng tròn (circular dependency) giữa các file

Circular dependency rất khó phát hiện: File A require File B, File B lại require File A. Node.js phá vỡ vòng lặp này bằng cách trả về một module object chưa hoàn chỉnh cho file đầu tiên — khiến các import của bạn bị resolve thành undefined.

// app.js requires routes/users.js
// routes/users.js requires app.js  ← vòng tròn!

// Cách sửa: tách logic dùng chung sang một file trung lập (ví dụ: db.js hoặc services/user.js)
// Cả hai file đều import từ đó — không còn vòng tròn nữa.

3. Middleware không được destructure từ export

Nếu file middleware dùng named exports, bạn cần destructure khi import. Nếu bỏ qua bước đó, bạn sẽ nhận được toàn bộ module object — chứ không phải bản thân function.

// middleware/auth.js
module.exports = { authMiddleware };

// SAI — lấy module object thay vì lấy function
const authMiddleware = require('./middleware/auth');
router.get('/profile', authMiddleware, getProfile); // 💥 object, không phải function

// ĐÚNG
const { authMiddleware } = require('./middleware/auth');

4. Nhầm lẫn giữa default export và named export (ES Modules)

// controllers/postController.js
export const getPosts = (req, res) => res.json([]);
// Không có default export!

// routes/posts.js — SAI
import getPosts from '../controllers/postController'; // undefined (không có default)
router.get('/', getPosts); // 💥

// ĐÚNG
import { getPosts } from '../controllers/postController';

5. Middleware factory thiếu câu lệnh return

Khi viết một factory tạo ra middleware mà quên câu lệnh return, Express sẽ nhận được undefined thay vì một function.

// SAI — trả về undefined
function rateLimiter(limit) {
  const fn = (req, res, next) => { next(); };
  // quên return fn!
}
router.get('/', rateLimiter(10), getUsers); // 💥

// ĐÚNG
function rateLimiter(limit) {
  return (req, res, next) => { next(); };
}
router.get('/', rateLimiter(10), getUsers);

6. Route file được load trước khi quá trình khởi tạo bất đồng bộ hoàn tất

Nếu một controller phụ thuộc vào kết nối DB hoặc config được load bất đồng bộ, việc require nó quá sớm sẽ trả về một module rỗng hoặc chưa được khởi tạo đầy đủ.

// Di chuyển phần khởi tạo lên trước khi đăng ký route
await connectDB(); // đợi bước này hoàn tất trước
const userRoutes = require('./routes/users'); // rồi mới load routes
app.use('/users', userRoutes);

Các Bước Debug Từng Bước

  • Đọc stack trace. Nó cho biết chính xác lời gọi router.get() hoặc app.post() nào bị lỗi.
  • Đi đến dòng đó. Log tất cả các argument trước khi truyền vào:

console.log({ myHandler, myMiddleware }); // tìm ra cái nào là undefined router.get('/path', myMiddleware, myHandler);

  
  - Tìm ra cái nào là `undefined`. Truy ngược lại nơi nó được import hoặc định nghĩa.
  - Sửa tên export, đường dẫn file, hoặc câu lệnh `return` còn thiếu.

## Kiểm Tra Sau Khi Sửa
Khởi động lại server và kiểm tra kết quả đầu ra:

node app.js

Nên thấy: Server running on port 3000

Không còn: Error: Route.get() requires a callback function


Gọi thử trực tiếp vào route bị ảnh hưởng:

curl http://localhost:3000/users

Kỳ vọng nhận được response hợp lệ — không phải crash


## Mẹo Phòng Tránh Lỗi Này

  - **Dùng TypeScript** — phát hiện sai lệch export/import ngay tại compile time, trước khi server khởi động.
  - **Nhất quán trong cách export** — chọn một trong hai: named exports (`module.exports = { fn }`) hoặc default export, rồi dùng nhất quán trong toàn project. Trộn lẫn cả hai là nguồn gốc đáng tin cậy của lỗi này.
  - **Cấm circular imports trong CI** — rule `import/no-cycle` từ `eslint-plugin-import` sẽ tự động phát hiện các trường hợp này.
  - **Luôn có return trong middleware factory** — nếu một function nhận argument và tạo ra middleware, nó phải kết thúc bằng câu lệnh `return`.

Related Error Notes