GitHub Actionsデプロイエラー - Jリーグクラブページ500エラー
ステータス
- 未解決
- 解決済み(2025-12-31)
発生日
2025-12-30 16:00 頃に初回発生
症状
GitHub ActionsでのNuxt generate(静的サイト生成)時に、特定のJリーグクラブページでランダムに500エラーが発生し、デプロイが失敗する。
エラーメッセージ
Errors prerendering:
├─ /financial-quiz/jleague/club/fcimabari/_payload.json (1077ms)
├── [500]
├── Linked from /financial-quiz/jleague/club/fcimabari
├── Linked from /financial-quiz/jleague/club/fcimabari?year=2024
├─ /financial-quiz/jleague/club/sagan/_payload.json (254ms)
├── [500]
├── Linked from /financial-quiz/jleague/club/sagan
├── Linked from /financial-quiz/jleague/club/sagan?year=2024
[error] Exiting due to prerender errors.
ELIFECYCLE Command failed with exit code 1.
影響を受けるクラブ(ランダムに変わる)
fcimabari(FC今治) - 発生sagan(サガン鳥栖) - 発生ehimefc(愛媛FC)parceiro(AC長野パルセイロ)
特徴
- ランダム性: 失敗するクラブが毎回異なる
- ローカルでは成功: ローカル環境の
pnpm generateは1414ルートすべて成功 - データは正常: 該当クラブの2024年データはJSONに存在
- パラメータ付き: すべてのエラーURLに
?year=2024が含まれている
失敗したGitHub Actions Run
| Run ID | 日時 | 失敗クラブ |
|---|---|---|
| 20591606645 | 2025-12-30 08:00 | fcimabari, sagan |
| 20590991809 | 2025-12-30 07:07 | ehimefc, sagan |
| 20590580759 | 2025-12-30 06:48 | fcimabari, parceiro |
原因(特定済み)
根本原因: crawlLinks + クエリパラメータ付きURL生成の組み合わせ
[club].vue の getClubUrl() 関数が ?year=2024 のようなクエリパラメータ付きURLを生成し、これが NuxtLink の :to 属性に渡される。
// apps/web/app/pages/financial-quiz/jleague/club/[club].vue:380-397
const getClubUrl = (clubId: string) => {
const query: Record<string, string> = {}
const year = periodLabels.value[periodIndex.value]
if (year) {
query.year = year // ← これがクエリパラメータを生成
}
// ...
return `/financial-quiz/jleague/club/${clubId}${queryString}`
}
nuxt.config.ts の nitro.prerender.crawlLinks: true により、Nitroのクローラーがこれらのクエリパラメータ付きURLも発見し、プリレンダリング対象として追加してしまう。
結果として:
- 60クラブ × 複数年度分のクエリ付きURLが大量に生成される
- CI環境で負荷が跳ね上がり、ランダムに500エラーが発生
試したこと
- ローカルでビルドし成功(1414ルート、エラーなし)
- データ存在確認しデータあり(fcimabari, sagan, ehimefc, parceiro すべて2024年データ存在)
ALL_CLUBS_WITH_TIER確認しクラブ定義あり
解決策(適用済み)
採用した対策: nitro.prerender.ignore でクエリパラメータ付きURLを除外
nuxt.config.ts に以下の設定を追加:
nitro: {
preset: "cloudflare-pages-static",
prerender: {
crawlLinks: true,
routes: ['/blog', '/'],
concurrency: 5,
ignore: [/\?/] // クエリパラメータ付きURLをプリレンダリング対象から除外
}
}
効果:
- ベースURL(
/financial-quiz/jleague/club/sagan)→ プリレンダリングされる ✓ - クエリ付き(
?year=2024)→ プリレンダリング対象外(CSR時は正常動作) - プリレンダリング対象URLが大幅に減り、CI環境での負荷とエラーリスクが低下
なぜクエリパラメータ付きURLをプリレンダリングしなくてよいのか
プリレンダリングのメリット(通常のURL)
- SEO: 検索エンジンのクローラーがJavaScriptを実行しなくてもコンテンツを読み取れる
- 初回表示速度: HTMLが事前生成されているため、アクセス時に即座にコンテンツが表示される
クエリパラメータ付きURL(?year=2024等)の場合
プリレンダリングする意味はほぼない:
- SEO的に不要: Googleは
?year=2024を別ページとしてインデックスしない。ベースURL(/financial-quiz/jleague/club/sagan)がインデックスされれば十分 - ユーザー導線: 通常はベースURLからアクセスして、UI操作で年度を切り替える
- URL共有時の影響: クエリパラメータ付きURLを共有した場合、ベースのHTMLが返された後にクライアントサイドで年度が切り替わる(一瞬の切り替えがあるだけで実用上問題ない)
今回のignore設定の意味
ignore: [/\?/] // クエリパラメータ付きURLを除外
これは本来プリレンダリングする必要がなかったURLを除外しただけであり、機能的なデメリットはない。むしろ不要なプリレンダリングを削減することでビルド時間短縮とCI安定性向上に寄与する。
クエリパラメータを使用している全箇所
| ファイル | パラメータ | 用途 |
|---|---|---|
financial-quiz/jleague/club/[club].vue | year, tab, chartTab | 年度・タブ状態の保持 |
japanese-writing-quiz/all.vue | correct, total | クイズ結果の表示 |
japanese-writing-quiz/punctuation.vue | correct, total | クイズ結果の表示 |
japanese-writing-quiz/modification-order.vue | correct, total | クイズ結果の表示 |
japanese-writing-quiz/particles.vue | correct, total | クイズ結果の表示 |
全て ignore: [/\?/] で除外されるが、問題なし:
- ベースURLはプリレンダリングされる
- クエリパラメータはクライアントサイドで処理される設計
- SEO的にクエリ付きURLをインデックスする必要がない
検討したが採用しなかった対策
crawlLinks: falseにして routes を明示的に指定- 効果的だが新しいコンテンツ追加時にroutesの更新が必要になり運用負荷が高い
concurrencyをさらに下げる(2〜4)- 安定性は増すがビルド時間が長くなる。根本解決ではない
- デバッグログを出す(
DEBUG=nitro:*orNITRO_PRERENDER_LOG_LEVEL=debug)- 原因特定には有効だが、根本解決ではない
関連ファイル
apps/web/app/pages/financial-quiz/jleague/club/[club].vueapps/web/app/composables/jleague/useJLeagueData.tsapps/web/data/j-league-data.json.github/workflows/deploy.yml
適用結果(2025-12-31)
デプロイ成功
| Run ID | 結果 | 詳細 |
|---|---|---|
| 20608145403 | ✅ 成功 | ignore設定適用後 |
| 20608097000 | ❌ 失敗 | ignore設定適用前 |
| 20607978004 | ❌ 失敗 | ignore設定適用前 |
ビルドログの確認
[info] [nitro] Prerendering 227 initial routes with crawler
[info] [nitro] Prerendered 1423 routes in 104.204 seconds
- プリレンダリング: 1423 routes(エラーなし)
- 所要時間: 104秒
?year付きURL: 0件(ignore設定により除外成功)
concurrency設定
ignore設定により負荷が下がったため、concurrency はデフォルト(10)に戻した。
明示的に指定しない場合、Nitroのデフォルト値10が適用される。
次のアクション
- 根本原因を特定(crawlLinks + クエリパラメータ付きURL)
-
nitro.prerender.ignoreでクエリパラメータ付きURLを除外 - GitHub Actionsでデプロイが成功するか確認
- デプロイ成功後、
concurrencyをデフォルトの10に戻す(ignore設定で負荷が下がったため)