The Error
Error: Route.get() requires a callback function but got a [object Undefined]
Your Express server crashes at startup โ before it handles a single request. The stack trace points straight to the offending router.get(), app.get(), or router.post() call.
Why This Happens
Express validates every argument you pass to a route. Pass anything that isn't a function โ including undefined โ and it throws immediately. No recovery, no fallback.
The root cause is almost always one of two things:
- A variable that resolved to
undefinedbecause of an import or require problem - A function that doesn't exist at the path you're importing from (named export mismatch)
Most Common Causes and Fixes
1. Named export mismatch (most frequent)
You export a function under one name but import it under a different one. The result is silently undefined โ no warning, just a crash at startup.
// controllers/userController.js
const getUsers = (req, res) => res.json([]);
module.exports = { getUsers };
// routes/users.js โ WRONG
const { getAllUsers } = require('../controllers/userController'); // undefined!
router.get('/', getAllUsers); // ๐ฅ crash
// routes/users.js โ CORRECT
const { getUsers } = require('../controllers/userController');
router.get('/', getUsers);
Before registering the route, log what you actually imported:
const { getUsers } = require('../controllers/userController');
console.log(typeof getUsers); // 'function' = good, 'undefined' = problem
router.get('/', getUsers);
2. Circular dependency between files
A circular dependency is sneaky: File A requires File B, which requires File A back. Node.js breaks the cycle by returning an incomplete module object for the first file โ so your imports come out as undefined.
// app.js requires routes/users.js
// routes/users.js requires app.js โ circular!
// Fix: extract shared logic to a neutral file (e.g., db.js or services/user.js)
// Both files import from there โ no cycle.
3. Middleware not destructured from its export
If your middleware file uses named exports, you need to destructure on import. Skip that and you get the whole module object โ not the function itself.
// middleware/auth.js
module.exports = { authMiddleware };
// WRONG โ grabs the module object, not the function
const authMiddleware = require('./middleware/auth');
router.get('/profile', authMiddleware, getProfile); // ๐ฅ object, not a function
// CORRECT
const { authMiddleware } = require('./middleware/auth');
4. Default export vs named export confusion (ES Modules)
// controllers/postController.js
export const getPosts = (req, res) => res.json([]);
// No default export!
// routes/posts.js โ WRONG
import getPosts from '../controllers/postController'; // undefined (no default)
router.get('/', getPosts); // ๐ฅ
// CORRECT
import { getPosts } from '../controllers/postController';
5. Middleware factory missing a return statement
Write a factory that builds middleware, forget the return, and Express gets undefined instead of a function.
// WRONG โ returns undefined
function rateLimiter(limit) {
const fn = (req, res, next) => { next(); };
// forgot to return fn!
}
router.get('/', rateLimiter(10), getUsers); // ๐ฅ
// CORRECT
function rateLimiter(limit) {
return (req, res, next) => { next(); };
}
router.get('/', rateLimiter(10), getUsers);
6. Route file loaded before async initialization finishes
If a controller depends on a DB connection or config that loads asynchronously, requiring it too early hands you an empty or partially initialized module.
// Move initialization before route registration
await connectDB(); // wait for this first
const userRoutes = require('./routes/users'); // then load routes
app.use('/users', userRoutes);
Step-by-Step Debugging
- Read the stack trace. It tells you exactly which
router.get()orapp.post()call failed. - Go to that line. Log every argument before passing it:
console.log({ myHandler, myMiddleware }); // spot the undefined router.get('/path', myMiddleware, myHandler);
- Find the `undefined` one. Trace it back to where it was imported or defined.
- Fix the export name, file path, or missing `return` statement.
## Verify the Fix
Restart the server and check the output:
node app.js
Should see: Server running on port 3000
No more: Error: Route.get() requires a callback function
Hit the affected route directly:
curl http://localhost:3000/users
Expect a valid response โ not a crash
## Tips to Avoid This
- **Use TypeScript** โ catches export/import mismatches at compile time, before the server ever starts.
- **Stay consistent with exports** โ pick either named exports (`module.exports = { fn }`) or a default export and stick to one style per project. Mixing both is a reliable source of this bug.
- **Ban circular imports in CI** โ the `import/no-cycle` rule from `eslint-plugin-import` catches these automatically.
- **Always return from middleware factories** โ if a function takes arguments and produces middleware, it must end with a `return` statement.

