Express.jsで「Route.get() requires a callback function but got [object Undefined]」を修正する方法

beginner💚 Node.js2026-05-20| Node.js 14以降、Express.js 4.x、任意のOS(Linux/macOS/Windows)

Error Message

Error: Route.get() requires a callback function but got a [object Undefined]
#express#ルーティング#ミドルウェア#undefined#nodejs

エラーの内容

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

Expressサーバーが起動時にクラッシュします — リクエストを1件も処理する前に。スタックトレースは問題のある router.get()app.get()、または router.post() の呼び出し箇所を直接指し示しています。

発生原因

Expressはルートに渡されたすべての引数を検証します。関数以外のもの — undefined を含む — を渡すと即座にエラーをスローします。リカバリも、フォールバックもありません。

根本原因はほぼ必ず次の2つのどちらかです:

  • importまたはrequireの問題により undefined に解決された変数
  • インポート元のパスに存在しない関数(名前付きエクスポートの不一致)

よくある原因と修正方法

1. 名前付きエクスポートの不一致(最も多いケース)

ある名前で関数をエクスポートし、別の名前でインポートしてしまうパターンです。結果はサイレントな undefined となり — 警告なしに起動時クラッシュが発生します。

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

// routes/users.js — 誤り
const { getAllUsers } = require('../controllers/userController'); // undefined!
router.get('/', getAllUsers); // 💥 クラッシュ

// routes/users.js — 正しい
const { getUsers } = require('../controllers/userController');
router.get('/', getUsers);

ルートを登録する前に、実際にインポートされた内容をログ出力して確認しましょう:

const { getUsers } = require('../controllers/userController');
console.log(typeof getUsers); // 'function' = 正常、'undefined' = 問題あり
router.get('/', getUsers);

2. ファイル間の循環依存

循環依存は気づきにくいものです:ファイルAがファイルBをrequireし、ファイルBがファイルAをrequireし返す状況です。Node.jsはこのサイクルを、最初のファイルに対して不完全なモジュールオブジェクトを返すことで解消します — その結果、インポートが undefined になります。

// app.js は routes/users.js を require する
// routes/users.js は app.js を require する  ← 循環!

// 修正方法:共有ロジックをニュートラルなファイル(例:db.js や services/user.js)に切り出す
// 両方のファイルはそこからインポートする — 循環なし。

3. エクスポートからミドルウェアを分割代入していない

ミドルウェアファイルが名前付きエクスポートを使用している場合、インポート時に分割代入が必要です。それを省略するとモジュールオブジェクト全体が取得されます — 関数そのものではなく。

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

// 誤り — モジュールオブジェクトを取得してしまい、関数ではない
const authMiddleware = require('./middleware/auth');
router.get('/profile', authMiddleware, getProfile); // 💥 関数ではなくオブジェクト

// 正しい
const { authMiddleware } = require('./middleware/auth');

4. デフォルトエクスポートと名前付きエクスポートの混同(ESモジュール)

// controllers/postController.js
export const getPosts = (req, res) => res.json([]);
// デフォルトエクスポートなし!

// routes/posts.js — 誤り
import getPosts from '../controllers/postController'; // undefined(デフォルトなし)
router.get('/', getPosts); // 💥

// 正しい
import { getPosts } from '../controllers/postController';

5. ミドルウェアファクトリにreturn文がない

ミドルウェアを生成するファクトリを書いて return を忘れると、Expressは関数の代わりに undefined を受け取ります。

// 誤り — undefinedを返す
function rateLimiter(limit) {
  const fn = (req, res, next) => { next(); };
  // fnをreturnし忘れている!
}
router.get('/', rateLimiter(10), getUsers); // 💥

// 正しい
function rateLimiter(limit) {
  return (req, res, next) => { next(); };
}
router.get('/', rateLimiter(10), getUsers);

6. 非同期の初期化完了前にルートファイルが読み込まれる

コントローラーが非同期で読み込まれるDB接続やコンフィグに依存している場合、早すぎるタイミングでrequireすると、空または部分的に初期化されたモジュールが返されます。

// ルート登録前に初期化を完了させる
await connectDB(); // まずこれを待つ
const userRoutes = require('./routes/users'); // それからルートを読み込む
app.use('/users', userRoutes);

ステップバイステップのデバッグ方法

  • スタックトレースを読む。どの router.get() または app.post() 呼び出しが失敗したかを正確に示しています。
  • その行に移動し、渡す前にすべての引数をログ出力する:

console.log({ myHandler, myMiddleware }); // undefinedを特定する router.get('/path', myMiddleware, myHandler);

  
  - `undefined` になっているものを見つけ、インポートまたは定義された箇所まで遡る。
  - エクスポート名、ファイルパス、または不足している `return` 文を修正する。

## 修正の確認
サーバーを再起動して出力を確認します:

node app.js

表示されるべき内容: Server running on port 3000

表示されないはず: Error: Route.get() requires a callback function


該当ルートに直接アクセスして確認します:

curl http://localhost:3000/users

期待する結果:正常なレスポンス — クラッシュではなく


## 再発防止のヒント

  - **TypeScriptを使用する** — サーバーが起動する前のコンパイル時にエクスポート/インポートの不一致を検出します。
  - **エクスポートスタイルを統一する** — 名前付きエクスポート(`module.exports = { fn }`)かデフォルトエクスポートのどちらかを選び、プロジェクト全体で一貫したスタイルを維持する。両方を混在させるとこのバグの温床になります。
  - **CIで循環インポートを禁止する** — `eslint-plugin-import` の `import/no-cycle` ルールで自動的に検出できます。
  - **ミドルウェアファクトリには必ずreturnを書く** — 引数を受け取ってミドルウェアを生成する関数は、必ず `return` 文で終わらなければなりません。

Related Error Notes