こんにちは、かつコーチです。
これまでNuxt.jsシリーズでは、ルーティングやデータ取得、サーバーAPIなど基本機能を一通り解説してきました。
ここからは少し毛色を変えて、実践Tips・つまずき解決編です。
今回は、Nuxtを触っていると本当によく出会うエラーを、原因と解決法のセットでまとめます。
エラーメッセージを見て固まってしまう前に、パターンを知っておけば対処のスピードがぐっと上がります。
Nuxtでエラーが出やすい場面
Nuxtのエラーは、大きく3つの場面で発生しやすい傾向があります。
1つ目は、モジュールのインストール漏れによる起動時エラーです。
2つ目は、SSRとCSRの結果が食い違うことで起きるhydration系エラーです。
3つ目は、開発サーバー起動時のポート競合など環境まわりのエラーです。
この3つを頭に入れておくと、エラーメッセージを見たときに「どのカテゴリの話か」がすぐに見えてきます。
よくあるエラーとBefore/Afterでの対処
エラー1: モジュール未インストールによる起動エラー
nuxt.config.tsにmodulesを追加したのに、モジュール本体をインストールし忘れるとエラーになります。
[nuxt] Error: Cannot find module '@pinia/nuxt'
Require stack:
- /project/nuxt.config.ts
原因は単純で、設定ファイルに書いただけでモジュールが自動で入るわけではないことです。
// ❌ Before: nuxt.config.tsに書いただけでインストールしていない
export default defineNuxtConfig({
modules: ["@pinia/nuxt"],
});
# ✅ After: モジュール本体を先にインストールする
npm install @pinia/nuxt pinia
// nuxt.config.tsはこのままでOK
export default defineNuxtConfig({
modules: ["@pinia/nuxt"],
});
modules配列に名前を書く作業と、パッケージをインストールする作業はセットだと覚えておきましょう。
エラー2: Hydration mismatch(サーバーとクライアントの表示不一致)
サーバーで生成したHTMLと、ブラウザ側で再構築したHTMLが一致しないと出るエラーです。
[Vue warn]: Hydration node mismatch:
- rendered on server: <span>2026-08-22 10:30:00</span>
- expected on client: <span>2026-08-22 10:30:04</span>
原因の多くは、Date.now()やMath.random()など、実行のたびに結果が変わる処理を描画中に呼んでいることです。
<!-- ❌ Before: サーバーとクライアントで結果が変わる -->
<script setup lang="ts">
const now = new Date().toLocaleString();
</script>
<template>
<span>{{ now }}</span>
</template>
<!-- ✅ After: onMountedでクライアント側だけに反映する -->
<script setup lang="ts">
import { ref, onMounted } from "vue";
const now = ref<string | null>(null);
onMounted(() => {
now.value = new Date().toLocaleString();
});
</script>
<template>
<span>{{ now ?? "読み込み中..." }}</span>
</template>
私が初めてこのエラーに遭遇したときは、コンソールに赤い警告が出ているだけで画面自体は正常に見えたため、しばらく放置してしまいました。
ですが本番環境ではチラつきの原因になっていて、後から気づいて修正した経験があります。
[Vue warn]: Hydration node mismatchが出たら、時刻・乱数・window参照を疑うのが第一歩です。
エラー3: 開発サーバーのポート競合エラー
npm run devを実行したときに、ポートがすでに使われていて起動できないことがあります。
ERROR Port 3000 is already in use
原因は、前回のNuxtプロセスが正常終了せずに残っていることがほとんどです。
# ❌ Before: エラーを無視して何度もdevを叩いてしまう
npm run dev
npm run dev
npm run dev
# ✅ After: ポートを使っているプロセスを特定して終了する
lsof -i :3000
kill -9 <表示されたPID>
npm run dev
もしくは、Nuxt側でポートを指定して起動する方法もあります。
# ✅ After(別解): 別ポートで起動する
npm run dev -- --port 3001
ターミナルを閉じずにCtrl+Cで正しく終了する癖をつけておくと、この問題自体を減らせます。
エラー4: useFetchのURLが相対パスで解決できないエラー
サーバーサイドの処理内で相対パスのAPIを呼ぶと、接続エラーになることがあります。
FetchError: [POST] "/api/posts": <no response> ECONNREFUSED
サーバーサイドで実行される処理は、ブラウザのようにホストを自動補完してくれません。
// ❌ Before: サーバーサイドで相対パスをそのまま使う
const { data } = await useFetch("/api/posts");
// ✅ After: server/api配下の内部呼び出しは相対パスのままでよいが、
// 外部APIを叩く場合は絶対URLで組み立てる
const config = useRuntimeConfig();
const { data } = await useFetch(`${config.public.apiBase}/posts`);
server/api/内のAPIを呼ぶだけなら相対パスで問題ありませんが、外部の別サーバーを叩く場合は絶対URLが必須です。
このあたりを混同すると、ローカルでは動くのに本番だけエラーになる、という状態にハマりやすいので注意してください。
応用:エラーを未然に防ぐ習慣
nuxi typecheckでビルド前に気づく
エラーの多くは、実行してから初めて気づくものです。
nuxi typecheckコマンドを使うと、TypeScriptの型エラーを事前に洗い出せます。
npx nuxi typecheck
CI(継続的インテグレーション)にこのコマンドを組み込んでおくと、本番反映前にミスを検知できます。
エラーメッセージは最初の1行だけでなく全体を読む
Nuxtのエラーは、原因の手がかりがスタックトレースの途中に埋もれていることがよくあります。
最初の1行だけで判断せず、atから始まる行を追ってどのファイル・どの処理で起きているかを確認する習慣をつけましょう。
まとめ
この記事のポイント
- Nuxtのエラーは「モジュール未インストール」「hydration不一致」「環境まわり」の3系統に大別できる
modulesに書くだけでなくパッケージのインストールも忘れずに行う- hydrationエラーは時刻や乱数などサーバー・クライアントで結果が変わる処理が原因になりやすい
- ポート競合はプロセスの終了漏れが原因のことが多い
- 外部APIを呼ぶ
useFetchは絶対URLで組み立てる
次に読むべき記事
次回は、useFetchがSSRとCSRで二重に実行されてしまうという、もう少し踏み込んだつまずき事例を紹介します。