GEMINI LABEN
NANOLITE — Nano Banana 2 Liteが登場しました。Googleで最も速く、最もコスト効率の高いGemini Imageモデルで、軽量な画像生成を安く回したい用途に向いていますOMNIFLASH — Gemini Omni Flashがpublic previewになりました。ネイティブにマルチモーダルなモデルで、企業や開発者が独自の動的な動画ワークフローを構築できますAGENTS — Managed Agentsが拡張されました。background: trueでサーバー側の非同期実行とポーリング、リモートMCPサーバー連携、対話をまたぐ認証情報のリフレッシュに対応しますMEMORY — Memory BankのIngestEvents APIが一般提供になりました。イベントの取り込みとメモリ生成を分離し、コンテンツを継続的にストリームできますTHROUGHPUT — Provisioned Throughputで、同一モデル・同一リージョンに対して最大7件の保留オーダーを提出できるようになりましたDEPRECATE — 画像生成モデルは8月17日に、Gemini Enterprise Agent PlatformのGrok 4.1系は8月20日に停止される予定ですNANOLITE — Nano Banana 2 Liteが登場しました。Googleで最も速く、最もコスト効率の高いGemini Imageモデルで、軽量な画像生成を安く回したい用途に向いていますOMNIFLASH — Gemini Omni Flashがpublic previewになりました。ネイティブにマルチモーダルなモデルで、企業や開発者が独自の動的な動画ワークフローを構築できますAGENTS — Managed Agentsが拡張されました。background: trueでサーバー側の非同期実行とポーリング、リモートMCPサーバー連携、対話をまたぐ認証情報のリフレッシュに対応しますMEMORY — Memory BankのIngestEvents APIが一般提供になりました。イベントの取り込みとメモリ生成を分離し、コンテンツを継続的にストリームできますTHROUGHPUT — Provisioned Throughputで、同一モデル・同一リージョンに対して最大7件の保留オーダーを提出できるようになりましたDEPRECATE — 画像生成モデルは8月17日に、Gemini Enterprise Agent PlatformのGrok 4.1系は8月20日に停止される予定です
記事一覧/API / SDK
API / SDK/2026-05-16中級

Next.js App Router の Server Actions から Gemini API を呼ぶときのエラー診断と解決策

Next.js App Router の Server Actions で Gemini API を呼ぶときに出る環境変数の undefined、ストリーミング不可、デプロイ後のみ出る Internal Server Error など実際のエラーと解決策をまとめました。

Gemini API191Next.js2Server ActionsApp Routerトラブルシューティング30

「ローカルでは動くのにデプロイ後だけ壊れる」——この一言で何時間も溶かしてきた開発者は少なくないはずです。

このサイト(gemilab.net)自体を Next.js App Router で構築しているので、Gemini API との連携は私が日常的に触っているテーマです。廣川政樹として 2013 年にスマートフォンアプリ個人開発を始めて以来、累計 5,000 万 DL を超えるアプリ事業を一人で運営しながら複数の Web サービスも同時に動かしていると、デバッグに費やす時間の短縮が生産性を直接左右することを痛感します。

Server Actions から Gemini API を呼び出す際に繰り返し踏んだパターンを整理しておきます。環境変数の undefined、ストリーミングの非互換、Edge Runtime との衝突——それぞれ原因と対処をまとめました。

エラー1:環境変数が Server Actions 内で undefined になる

最もよく見かけるのが、環境変数の参照ミスです。Server Actions はサーバーサイドで実行されます。つまり、NEXT_PUBLIC_ プレフィックス付きの環境変数を使う必要はありません。しかし「クライアントコンポーネントでも使いたいから NEXT_PUBLIC_ を付けた」変数を Server Actions 内でも参照しようとすると混乱が生じます。

// ❌ 動くが API キーがクライアントバンドルに露出してしまう
'use server'
import { GoogleGenerativeAI } from '@google/generative-ai'
const genAI = new GoogleGenerativeAI(process.env.NEXT_PUBLIC_GEMINI_API_KEY ?? '')
 
// ✅ サーバー専用変数を使う(NEXT_PUBLIC_ なし)
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY ?? '')

.env.local は以下のように整理するのが安全です。サーバー専用の変数(GEMINI_API_KEY)とクライアントから参照可能な変数(NEXT_PUBLIC_)を明確に分けてください。

# サーバー専用(Server Actions・Route Handlers のみ)
GEMINI_API_KEY=YOUR_API_KEY_HERE
# クライアントでも使いたい情報のみ(API キーは含めない)
NEXT_PUBLIC_SITE_NAME=Gemini Lab

Vercel などのデプロイ環境では .env.local がそのままデプロイされないため、ダッシュボードから環境変数を手動設定する必要があります。「ローカルでは動くのにデプロイ後に GEMINI_API_KEY is undefined と出る」場合は、まず Vercel の Settings → Environment Variables を確認してください。私自身、ステージング環境と本番環境で環境変数の設定を分けて管理するようにしてから、この種のトラブルはほぼなくなりました。

エラー2:Server Actions からのストリーミングが動かない

「Gemini の generateContentStream を使いたいのに、Server Actions では上手く受け取れない」という相談をよく目にします。これは Next.js の仕様上の制限です。Server Actions は JSON シリアライズ可能な値しか返せませんAsyncGeneratorReadableStream をそのまま返そうとすると、型エラーまたはランタイムエラーになります。

// ❌ AsyncGenerator はシリアライズ不可のため失敗する
'use server'
export async function generateWithStream(prompt: string) {
  const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' })
  const result = await model.generateContentStream(prompt)
  return result.stream // ← シリアライズできないため失敗する
}

解決策は2つあります。

解決策 A:Route Handler に切り替える

ストリーミングが必要な場合は、Server Actions ではなく Route Handler(/app/api/generate/route.ts)を使うのが最もシンプルです。ReadableStream をそのまま Response に渡せるので、Gemini のチャンクをリアルタイムにクライアントへ流せます。

// app/api/generate/route.ts
import { GoogleGenerativeAI } from '@google/generative-ai'
import { NextRequest } from 'next/server'
 
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY ?? '')
 
export async function POST(req: NextRequest) {
  const { prompt } = await req.json()
  const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' })
  const result = await model.generateContentStream(prompt)
 
  const stream = new ReadableStream({
    async start(controller) {
      for await (const chunk of result.stream) {
        controller.enqueue(new TextEncoder().encode(chunk.text()))
      }
      controller.close()
    },
  })
 
  return new Response(stream, {
    headers: { 'Content-Type': 'text/plain; charset=utf-8' },
  })
}

解決策 B:Vercel AI SDK の createStreamableValue を使う

Vercel AI SDK を導入している場合は createStreamableValue を使えます。これは AsyncGenerator をシリアライズ可能な形式にラップするユーティリティで、Server Actions からでも利用できます。

'use server'
import { createStreamableValue } from 'ai/rsc'
import { GoogleGenerativeAI } from '@google/generative-ai'
 
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY ?? '')
 
export async function generateText(prompt: string) {
  const stream = createStreamableValue('')
  const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' })
 
  ;(async () => {
    const result = await model.generateContentStream(prompt)
    for await (const chunk of result.stream) {
      stream.update(chunk.text())
    }
    stream.done()
  })()
 
  return { output: stream.value }
}

個人的には、Gemini API のストリーミングには Route Handler を使うほうが、コードがシンプルで本番環境のログも追いやすいと感じています。Server Actions はストリーミングを伴わない処理(フォーム送信後の生成、バックグラウンドでのコンテンツ作成など)に向いています。

エラー3:ローカルでは動くのにデプロイ後だけ出る Internal Server Error

これが最も原因特定に時間がかかるパターンです。典型的な原因は3つあります。

原因 A:SDK のインスタンス化をモジュールのトップレベルで行っている

GoogleGenerativeAI のインスタンス生成をファイルのトップレベルに置くと、モジュール評価時に実行されます。特定の環境では環境変数がまだ読み込まれていないケースがあり、ここで失敗します。関数スコープ内に移動するだけで解決します。

// ❌ モジュールロード時に実行されるリスクがある
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!)
export async function myAction(input: string) { ... }
 
// ✅ 関数スコープ内に移動して安全に初期化
export async function myAction(input: string) {
  const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY ?? '')
  // ...
}

原因 B:Vercel のサーバーレス関数タイムアウト

Gemini API への呼び出しが長いプロンプトや大きなコンテキストで遅延した場合、Vercel Free プランの 10 秒タイムアウトに引っかかります。Route Handler に maxDuration を設定することで上限を引き上げられます(Pro プランが必要)。

// Route Handler の場合(Next.js 14.2+)
export const maxDuration = 60 // 秒

原因 C:Edge Runtime との非互換

export const runtime = 'edge' が残っているファイルでは、@google/generative-ai が利用する Node.js API が Edge Runtime で動きません。この設定を削除するか、明示的に Node.js runtime を指定してください。

// ❌ これがあると Gemini API が動かない
export const runtime = 'edge'
 
// ✅ 削除するか Node.js runtime を明示
export const runtime = 'nodejs'

Route Handler と Server Actions の使い分け基準

複数のプロジェクトを同時に運営する中で、次の基準が使いやすいと感じています。

Server Actions が向いているのは、フォーム送信後に Gemini API を呼んで結果をデータベースに保存する処理や、ボタン操作に連動した一回完結の生成処理です。Next.js のキャッシュ・再検証の仕組みとも相性が良いです。

Route Handler が向いているのは、Gemini API のストリーミングレスポンスをクライアントに流す場合や、外部サービスのウェブフックを受け取る場合です。また、アプリの複数の箇所から共有して使える API エンドポイントを設けたいときにも Route Handler のほうが管理しやすいです。

この判断を設計初期に固めておくだけで、後からの変更コストが大幅に減ります。アーティスト活動と並行して Web サービスを運営している私自身にとって、設計段階の小さな判断が後工程の手間を左右するという実感は日々あります。

デバッグ手順の優先順位

ローカルで再現しないエラーを追うときは、以下の順序で確認するのが効率的です。まず Vercel のビルドログを確認します。環境変数のエラーはランタイムではなくビルド時点で出ることが多いためです。次に Functions タブでタイムアウトと実行時間を確認します。ローカルでは瞬時に返ってくる処理も、Vercel の環境では遅延することがあります。

それでも再現しない場合は next startnext dev ではなく)をローカルで実行してみてください。next dev は開発用の最適化が入っており、本番との差異が出やすいです。next start は本番ビルドに近い状態で動作するため、デプロイ後のエラーをローカルで再現しやすくなります。

同じ課題に取り組んでいる方の参考になれば幸いです。

よくある追加の落とし穴

Server Actions 内で 'use client' ディレクティブを持つコンポーネントから直接インポートされた関数を呼ぼうとすると、予期せぬエラーが出ることがあります。'use server''use client' の境界は Next.js の内部で明確に管理されており、その境界をまたぐ呼び出し方は制限されています。

また、Server Actions を使って Gemini API に画像を送る場合も注意が必要です。ブラウザから受け取った File オブジェクトや Blob は、Server Actions を通じてそのまま Gemini API に渡せません。ArrayBuffer または Uint8Array に変換したうえで inlineData 形式にまとめる必要があります。この変換処理を忘れると、invalid argument: image data のようなエラーが静かに発生します。

複数のサービスを並行して開発していると、環境変数の命名規則が混在しがちです。プロジェクト初期から .env.local.example ファイルを作成し、どの変数が NEXT_PUBLIC_ を必要とするか、どの変数がサーバー専用かを明記しておくと、後からチームに加わった人にも分かりやすい構成になります。

エラーが出た際は、まずエラーメッセージをそのまま検索するのが最短ルートです。Gemini API のエラーコードには、対処法が比較的明確に記載されているものが多いです。それでも解決しない場合は、@google/generative-ai パッケージのバージョンを確認してください。マイナーバージョンのアップデートで API の挙動が変わることがあります。

シェア

お読みいただきありがとうございます

Gemini Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

API / SDK2026-06-22
Gemini API × Google Cloud 本番エラーを層で切り分ける診断手順
Gemini APIをGoogle Cloud本番環境で運用する際のエラーを体系的に診断。IAM権限・Vertex AI vs AI Studio・VPC・クォータ管理・サービスアカウント設定まで、実装コード付きで完全解説します。
API / SDK2026-06-21
Gemini API モデル非推奨・移行エラーの対処法
Gemini API でモデルが非推奨になった時の移行手順と、移行時に発生するエラーの対処法を詳しく解説します。
API / SDK2026-06-03
Gemini Live API の応答音声が速回しに聞こえる — サンプルレート取り違えの直し方
Gemini Live API の応答音声が甲高く速回しに聞こえる、あるいはノイズ混じりになる症状は、ほとんどが 24kHz の出力を別のサンプルレートで再生していることが原因です。ブラウザと iOS の両方で、取り違えを直す具体的なコードを記録します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →