蒼井凪
開発2026-06-04

Next.js App Router の generateStaticParams で日本語パスが404になる:二重エンコード問題の罠

encodeURIComponent を親切心でかけたら、本番だけ全滅した。

Next.js App Router で動的ルートを使っているとき、日本語を含むパスのページがVercel本番環境でのみ404になるケースがある。前の記事で日本語スラッグの全般的な問題を書いたが、generateStaticParams での二重エンコードは少し別の文脈で踏むことがあるので独立して書いておく。

踏んだ状況

app/[category]/[slug]/page.tsx のような構造で、スラッグがMarkdownのfrontmatterから来ていた。コンテンツ管理の都合でスラッグに日本語が混入していた。

generateStaticParams の実装はこうだった。

export async function generateStaticParams() {
  const posts = getAllPosts();
  return posts.map((post) => ({
    category: post.category,
    slug: encodeURIComponent(post.slug),
  }));
}

URLに日本語が入ることを考えて encodeURIComponent をかけた。むしろ正しい処置をしているつもりだった。

何が起きているか

Next.js の App Router は、generateStaticParams が返した値をビルド時にそのままファイルパスとして使う。そこに encodeURIComponent 済みの値を渡すと、Next.js がもう一度エンコードする

例えば ギター というスラッグなら:

  1. encodeURIComponent('ギター')%E3%82%AE%E3%82%BF%E3%83%BC
  2. Next.js が再エンコード → %25E3%2582%25AE%25E3%2582%25BF%25E3%2583%25BC

生成されるファイルのパスと、ブラウザが実際にリクエストするパスが食い違う。ローカルの開発サーバーはファジーにマッチングするので気づかない。Vercelの本番では静的ファイルがそのまま配信されるので、完全一致しないと404になる。

encodeURIComponent をかけないのが正解だ。

export async function generateStaticParams() {
  const posts = getAllPosts();
  return posts.map((post) => ({
    category: post.category,
    slug: post.slug, // 生の値をそのまま
  }));
}

page.tsx 側で使うときも同じ

generateStaticParams から渡ってくる params を使う側でも同様だ。

// app/[category]/[slug]/page.tsx
export default async function Page({
  params,
}: {
  params: { category: string; slug: string };
}) {
  // params.slug は生の値で来る(例:'ギター')
  // decodeURIComponent は不要
  const post = getPostBySlug(params.slug);
}

params.slug をそのままコンテンツ取得の検索キーとして使える。decodeURIComponent で解除しようとすると、今度はローカルで壊れる。

整理

| 場所 | やること | |---|---| | generateStaticParams の返り値 | 生の値そのまま。エンコード不要 | | page.tsxparams を使う側 | 生の値として受け取る。デコード不要 | | リンクの href に日本語スラッグを書く | これも生の値でいい。Next.js の Link が処理する |

Next.js はエンコード・デコードを自動でやる。人間が手を出すと壊れる。

根本的な対処

そもそも日本語スラッグは管理が面倒なので、最初からASCIIにしておくのが楽だ。frontmatterに slug フィールドを別途設けてASCIIで書くか、ファイル名をASCIIにして自動生成する設計にしておくと、この問題自体に踏まない。

※ 本記事にはアフィリエイトリンクが含まれます。

開発 一覧へ