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-04-27中級

Gemini API のファイル URI が突然 404 になる問題 — 48時間 TTL を前提にした設計の組み立て方

昨日まで動いていた Gemini API の画像/動画認識が、サーバー再起動後に急に動かなくなることがあります。原因は File API の48時間 TTL でした。検出方法と、TTL を前提にしたアプリ設計の組み立て方を実例で解説します。

gemini-api279file-api6troubleshooting57ttlproduction105

「昨日まで普通に画像認識が動いていたのに、今朝サーバーを再起動したら急にエラーが返ってくるようになった」— Gemini API を本番投入したばかりの個人開発者の方から、この相談を受けることがあります。エラーメッセージを見ると File ... is not foundINVALID_ARGUMENT が出ていて、コード自体は何も変えていません。原因がさっぱり分からず、半日溶けてしまうパターンです。

結論から書きます。Gemini File API でアップロードしたファイルには 48時間の TTL があり、それを過ぎると自動で削除されます。File URI(files/xxxx という識別子)を DB やキャッシュに保存して翌日使い回そうとすると、ある日突然 404 で落ちます。これは仕様であり、運用前提から見直す必要があります。

ここではなぜこの問題が起きるのかを公式仕様の側から整理した上で、TTL を前提にしたアプリ設計のパターンを3つに分けて紹介します。私自身が個人アプリで一度ハマってサーバー再起動後の早朝アラートで起こされた経験があるので、再発防止の観点から書いています。

まず起きていることを正確に把握する

最初にやるべきは、エラーメッセージを目視で確認するのではなく、File API でファイルの状態を能動的に取りにいくことです。client.files.get(name) を呼べば、そのファイルが今どういう状態にあるかが返ってきます。

# 何を解決するコード: 保存していた File URI が今も使えるか確認する
from google import genai
import os
 
client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
 
# DB やセッションから引いてきた File URI(例)
saved_file_name = "files/abc123def456"
 
try:
    file_info = client.files.get(name=saved_file_name)
    print(f"State: {file_info.state}")          # ACTIVE / PROCESSING / FAILED のいずれか
    print(f"Expiration: {file_info.expiration_time}")  # 削除予定時刻(UTC)
    print(f"URI: {file_info.uri}")
except Exception as e:
    # 404 系のエラーが返ってきたら既に削除されている
    print(f"File no longer exists: {e}")

このコードを動かすと、ファイルが生きていれば state=ACTIVEexpiration_time が返ります。expiration_time を見れば、「あと何時間で消える予定なのか」が分かります。ここが最重要ポイントで、File API は確定的に48時間で消えるとは限らず、設定や負荷状況で多少前後します。 つまりタイマーで「48時間後に消える」と決め打ちするのではなく、毎回 expiration_time を信頼するのが正しい設計です。

なお、404 エラーが返ってきたらファイルは既に削除されています。エラー文だけで「File API が壊れた」と思い込まずに、まずこの状態確認を挟むだけで原因の切り分けが10倍速くなります。

パターン1: 短命データはインラインで送る

そもそも File API を使わなくていいケースがあります。Gemini API は画像や PDF を inline data(base64 エンコードされたバイト列)として直接プロンプトに含められるため、20MB 以下のデータで「アップロード後すぐ使う」用途なら、File API を経由する必要はありません。

# 何を解決するコード: 小さい画像をインラインで送って TTL 問題を完全に回避する
from google import genai
from google.genai import types
import pathlib
 
client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
 
image_bytes = pathlib.Path("photo.jpg").read_bytes()
 
response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=[
        types.Part.from_bytes(data=image_bytes, mime_type="image/jpeg"),
        "この画像に写っているものを日本語で説明してください。",
    ],
)
print(response.text)
# 期待出力: 「夕焼けに染まった海岸線の写真です。中央に岩礁があり…」のような自然な日本語の説明

なぜこれが TTL 問題を解決するのか。インラインで送るとファイルはサーバー側に保存されず、その場でモデルに渡されて終わります。保存されないものは消えようがない — シンプルな話です。

私はチャットボット系のアプリでは、ユーザーが添付した画像はすべてインラインで送るようにしています。アップロード→保存→再読み込みの3往復が消えるので、レスポンスも目に見えて速くなります。20MB という上限はあるものの、スマホ撮影画像であれば事前に長辺を1568px に縮小しておけば、まず引っかかりません。

パターン2: 永続化が必要なら自分でストレージ + 都度再アップロード

動画解析や、繰り返し参照される大きな PDF など、本当に File API を使わないと厳しいケースもあります。その場合の正攻法は「File URI は揮発キャッシュとして扱い、原本は自分のストレージに保存しておく」設計です。

# 何を解決するコード: File URI が消えていたら自動で再アップロードする
import os
from google import genai
from google.genai import types
 
client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
 
def get_or_upload(local_path: str, cached_file_name: str | None) -> object:
    """既存の File URI が生きていれば再利用、なければ再アップロードする"""
    if cached_file_name:
        try:
            info = client.files.get(name=cached_file_name)
            if info.state.name == "ACTIVE":
                return info  # まだ生きているのでそのまま使う
        except Exception:
            pass  # 404 など — そのまま再アップロードへフォールスルー
 
    # 再アップロード
    uploaded = client.files.upload(file=local_path)
    # 重要: 新しい file.name を呼び出し側で保存し直すこと
    return uploaded
 
# 利用例
file = get_or_upload("video.mp4", cached_file_name="files/oldname123")
response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents=[file, "この動画の要点を3つに絞って教えてください。"],
)
print(response.text)

ポイントは2つあります。1つは、client.files.get を try で囲むこと。404 を例外で受け取って自然にフォールスルーさせると、コードがシンプルになります。もう1つは、新しい file.name を必ず呼び出し側で保存し直すこと。再アップロードしても古い URI には戻らないので、DB を更新しないと次回もまた再アップロードが走ります。

ストレージ側は、AWS S3、Cloudflare R2、Google Cloud Storage などコストの低い選択肢で十分です。私の場合は R2 を使っていて、ユーザーがアップロードした動画は永続化、Gemini に渡す File URI は「24時間で再生成し直してもいい」くらいの感覚で運用しています。

パターン3: 大量推論はバッチで TTL 内に終わらせる

File API の本来の使いどころは、1ファイルを複数回・短期間で参照するケースです。例えば1本の動画から「要約」「タグ抽出」「シーン検出」「テロップ起こし」を順に走らせるなら、毎回アップロードするより File URI を取り回したほうがトークンコストもレイテンシも下がります。

このときに気をつけたいのは、処理を48時間以内に終わらせることです。バッチ処理が長引いて TTL を超えると、バッチの途中で 404 が出始めます。私の経験則では、24時間を超えそうなジョブは「バッチを分割して、各バッチの先頭で File API にアップロードする」設計に切り替えると安全です。

具体的には、ジョブキューを設計するときに「アップロード→処理→(必要なら)削除」を1つのトランザクション単位として扱い、48時間を超えないように分割します。ジョブキュー側で TTL 切れを起こしたタスクは、再アップロード→再キューする処理を入れておくと、運用中の事故をさらに減らせます。

どのパターンを選ぶか

私が普段使っている判断基準はシンプルです。「このファイルを今後数時間以内にもう一度参照するか?」と自問してみます。答えが「いいえ」ならインライン(パターン1)。答えが「はい」で、かつ自前ストレージに置いても運用コスト的に痛くないサイズならパターン2。本当にバッチ処理として大量推論を回す必要がある場合のみパターン3、という流れです。

一つのアプリの中で混在しても問題ありません。私が運営しているアプリでは、ユーザーが添付したスクリーンショットは小さくて1回しか使わないのでインラインで送り、長尺の動画ファイルは R2 に永続化してパターン2で扱う、という使い分けにしています。重要なのは「とりあえず File API にアップロードして URI を保存する」という安易な既定路線を取らないことです。それが深夜のアラートを生む原因になります。

やってはいけない設計

ここまでで何度か出てきていますが、明示的に書き出しておきます。

  • File URI を「永続的な ID」として DB に保存する: 48時間後に必ず無効になります。一見テストでは動くため、本番投入後に時限爆弾化します
  • expiration_time を確認せずに使う: 「アップロードして30秒以内に使うから大丈夫」というコードでも、再試行ロジックが入ると48時間越えに化けることがあります
  • 404 を握りつぶす: 「ファイルが見つからない」というエラーは、ユーザー体験を損なう前にロガーへ警告として残しておくべき情報です。サイレントに失敗させると検知が遅れます
  • 巨大な動画ファイルを毎回アップロードし直す: TTL 対策として全部再アップロードにすると、コストとレイテンシが膨らみます。インライン・短期キャッシュ・自前ストレージの組み合わせで設計するのが現実解です

次にやること

ここまでの内容を、明日以降のあなたのコードに1つだけ反映するなら、「File URI を保存しているコードに client.files.get の状態確認を1行挟む」 のが一番効きます。これだけで「昨日まで動いていたのに今朝から 404」というアラートはほぼ消えます。

私が運営しているアプリでは、ユーザーが画像/動画を添付したタイミングでメタデータと一緒に保存先 URI(自前ストレージのもの)を持ち、Gemini に渡すときだけ File API にアップロードして使い捨てる、という形に落ち着きました。シンプルですが、TTL に振り回されることがなくなります。

File API 自体の基本的な使い方は Files API ガイド に詳しくまとまっています。大きなコンテキストを繰り返し参照したい場合は Context Caching ガイド のほうが本質的な解になることもあるので、合わせて検討してみてください。エラーハンドリング全般のパターンは リトライパターン も参考になります。

シェア

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

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

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

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

関連記事

API / SDK2026-05-31
Gemini APIで「Unsupported MIME type」エラーが出るときの原因と対処
画像や音声をGemini APIに渡したときに発生する『Unsupported MIME type』エラーを、MIMEタイプの綴り間違い・octet-stream問題・非対応フォーマットの3つの観点から切り分けて、確実に動くコードで解決します。
API / SDK2026-05-23
Gemini API のストリーミングが本番で「途中で切れる」とき、私が試している原因切り分けの順序
Gemini API のストリーミング応答が本番で途中で切れる症状を、ネットワーク・SDK・サーバー側のどこから疑うかの順序を、個人開発で実際に踏んだ事例ごとに整理しました。
API / SDK2026-05-12
Gemini File APIのファイルが「PROCESSING」のまま止まる:タイムアウト処理とリトライ設計
Gemini File APIでアップロードしたファイルがPROCESSING状態のまま進まない問題を解説。ポーリングの正しい実装・タイムアウト設計・失敗時のクリーンアップまで、実際のコードで解決します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →