Gemini Live API のセッションが突然切れる 3 つの制限
リアルタイム音声対話の検証中、Gemini Live API のセッションが切れました。切れること自体は仕様として知っていましたが、いざ切れると「今のはどの制限に当たったのか」が分かりません。調べていくと、切れる理由は 3 層あって、対処がそれぞれ違うことが分かりました。1 つの「タイムアウト」として扱うと、対処を取り違えます。
この記事は公式ドキュメント(2026-08 時点)の整理と、自前の検証で得た実測値・実装パターンをまとめたものです。数値は変わり得るので、各層に出典を付けています。
第 1 層: セッション時間そのものの上限
セッション管理のドキュメントにこうあります。
Without compression, audio-only sessions are limited to 15 minutes, and audio-video sessions are limited to 2 minutes.
既定では音声のみ 15 分、音声+映像だと 2 分です。映像を足すと上限が 2 分になり、知らずに当たると短すぎて設定ミスを疑うと思います(私の検証は音声のみの構成なので、2 分の上限には自分では当たっておらず、ドキュメントの記載)。
対処は contextWindowCompression の有効化です。
{
"setup": {
"contextWindowCompression": { "slidingWindow": {} }
}
}これを有効にすると、コンテキストを sliding window で圧縮する代わりに、時間制限が外れます。ドキュメントには "To enable longer sessions, and avoid abrupt connection termination, you can enable context window compression" とあり、延長後は無制限です。
第 2 層: WebSocket 接続の寿命
セッションの上限を外しても、WebSocket 接続そのものが約 10 分で切られます。
The lifetime of a connection is limited as well, to around 10 minutes.
接続の切断に備えて、サーバー側に 2 つの仕組みがあります。
- 予告: 切断前にサーバーから
GoAwayメッセージが届きます。残り時間(timeLeft)付きです - 引き継ぎ:
sessionResumptionを setup で有効にしておくと、サーバーから resumption ハンドルが随時届きます。切断後、そのハンドルを次の接続の setup に渡すと会話状態を引き継げます。ハンドルは最終切断から 2 時間有効です
つまり Live API は、接続が切れるたびに作り直し、会話状態をハンドルで次の接続へ引き継ぐ使い方を前提にしています。接続の確立自体は実測で 340〜480ms(Node 22、データセンター級回線、v1beta WebSocket 直結。SDK なしで WebSocket を直接叩く方法)なので、接続し直すコストは小さいです。
GoAway が来ない切断にも備える
ただし、GoAway が常に来るとは限りません。公式フォーラムには、2026-08-04 ごろから gemini-3.1-flash-live-preview で GoAway が来ないままコード 1006 でハード切断される回帰の報告があり、8 月中旬に部分的に回復した、という経過が記録されています。preview モデルでは、このような挙動の変化が起きます。
そのため、GoAway を受けてから接続し直す処理と、予告なしに切れたときに無条件で再接続する処理の両方を持たせます。GoAway が届くことを、接続を保つ前提にはしない方が安全です。
第 3 層: ephemeral token の寿命
クライアントから直接接続する構成では、API キーの代わりに ephemeral token を使います。この token に 3 つの時限が付いています(ephemeral tokens のドキュメント、2026-08 時点)。
- expireTime: token 自体の有効期限。既定 30 分
- newSessionExpireTime: その token で「新しいセッションを開始できる」期限。既定 1 分
- 単回使用: 1 つの token で開始できるセッションは 1 つ
危ないのは newSessionExpireTime の 1 分です。「token を取っておいて、ユーザーが開始ボタンを押したら接続」という自然な実装は、取得から接続までが 1 分を超えた時点で接続を拒否されます。「取得→即接続」を 1 つの操作として実装する必要があります。
再接続との組み合わせには但し書きがあって、ドキュメントには「expireTime の範囲内なら、sessionResumption を使った 10 分ごとの再接続は同じ token でできる(uses: 1 でも)」という記載があります。とはいえ expireTime 既定 30 分を超えて会話が続く可能性があるなら、結局は token を再発行する処理が要ります。私は再接続のたびに新しい token を取得する設計にしました。分岐が 1 本減り、「この再接続は同じ token でよいか」を考えなくて済みます。
3 層をまとめると
- セッション時間(音声のみ 15 分 / 映像あり 2 分)→
contextWindowCompressionで解除 - 接続寿命(約 10 分、GoAway 予告つき・ただし来ないこともある)→
sessionResumptionハンドルで張り替え - token 寿命(expireTime 30 分 / 新規セッション開始は 1 分 / 単回使用)→ 取得→即接続、再接続時は再発行
「切れた」ときの切り分けもこの順です。開始直後に接続すら張れないなら token(第 3 層)、10 分前後で切れたなら接続寿命(第 2 層)、映像ありで 2 分なら第 1 層です。
実装パターン: GoAway を受けたら会話の区切りまで待って接続し直す
GoAway を受けてすぐ張り替えると、会話の途中で無音が挟まります。私は GoAway をアプリのイベントとして扱い、timeLeft の範囲内で会話の区切り(進行フェーズの切り替わり)まで待ってから張り替える形にしました。張り替え中の無音時間は計測項目に入れています。この設計がうまくいったかは、無音にユーザーが気付くかどうかで決まるからです。
切断の原因を 3 層で切り分け、GoAway が来ない切断にも備える
- 「セッションが切れる」原因は 3 層ある。どれに当たったかを先に切り分ける
contextWindowCompressionとsessionResumptionは、実用上ほぼ必須の setup オプションとして最初から入れておく- GoAway が来ない切断のパスを必ず用意する。preview モデルでは予告メカニズム自体が不安定になることがある
- ephemeral token は「取得→即接続」。取得して置いておいた token は
newSessionExpireTime(既定 1 分)を過ぎると使えない - 数値(15 分 / 10 分 / 2 時間 / 30 分 / 1 分)はすべて 2026-08 時点のドキュメント値。設計はこの数値に依存しすぎない形にしておく