◉GEMINI LABEN
●ARGON — gemini-4-argon が 10/13 に GA。複雑なコーディング・エージェント・数学・科学向けです●DEEP RES — 旧 Deep Research エージェントは 10/23 に停止済み。呼び出しが失敗する場合は deep-research-preview-04-2026 へ●NANO — gemini-nano-banana-2.1 が GA(10/06)。gemini-3.1-flash-image は非推奨で停止日は未発表です●CLI — Gemini API CLI(gemini-api)がベータで登場(10/27)。エージェントやCI向けのゼロ依存クライアントです●STORE — 新規の有料プロジェクトでは生成リクエストの保存(store)が既定でオンになります(10/26)●NEW — クラッシュ報告を毎回ゼロから読ませない — 既知バグ早見表を先に grep し…●ARGON — gemini-4-argon が 10/13 に GA。複雑なコーディング・エージェント・数学・科学向けです●DEEP RES — 旧 Deep Research エージェントは 10/23 に停止済み。呼び出しが失敗する場合は deep-research-preview-04-2026 へ●NANO — gemini-nano-banana-2.1 が GA(10/06)。gemini-3.1-flash-image は非推奨で停止日は未発表です●CLI — Gemini API CLI(gemini-api)がベータで登場(10/27)。エージェントやCI向けのゼロ依存クライアントです●STORE — 新規の有料プロジェクトでは生成リクエストの保存(store)が既定でオンになります(10/26)●NEW — クラッシュ報告を毎回ゼロから読ませない — 既知バグ早見表を先に grep し…
記事一覧/API / SDK
◈ API / SDK/2026-10-30中級

ADK のエージェントが「API key expired」で一度も動かない。文面ではなく reason を読むと、疑う順番が決まりました

ADK 経由で 400 INVALID_ARGUMENT「API key expired. Please renew the API key.」が毎回返るとき、期限切れと決めつける前に確かめる順番を整理しました。reason の読み方、環境変数と .env の食い違い、鍵の状態を REST で切り分ける短いスクリプト付きです。

ADK3Gemini API253API キー3トラブルシューティング39環境変数400 INVALID_ARGUMENT

夜遅くに ADK でエージェントを一つ組み、adk run を叩いた直後のことです。画面に出たのは 400 INVALID_ARGUMENT、そして「API key expired. Please renew the API key.」の一行でした。

鍵を作ったのは数日前です。期限切れと言われても、心当たりがありません。それでも文面どおりに受け取って鍵を作り直し、貼り替え、同じ場所で同じエラーを見て、肩が落ちる——そんな回り道を、私自身、似た形で何度かしてきました。

最初にお伝えしたいのは、この文面は原因を言い当てていないかもしれない、ということです。見るべきは文章ではなく、同じ応答の中にある reason のほうでした。

なお、この記事は私の手元で障害を再現した記録ではありません。GitHub の gemini-cli リポジトリに 2026 年 4 月 7 日付で立った報告(#24831)の文面と、Gemini API 公式の API キーのページにもとづく、疑う順番の整理です。その報告にはコメントも対処も付いておらず、原因は公開されていません。ですから「これが答えです」とは書けず、「ここから潰すと迷いにくい」という線引きまでをお渡しします。

報告されている文面を、そのまま分解する

報告に載っていた内容は、次のとおりです。

google.genai.errors.ClientError: 400 INVALID_ARGUMENT
message: "API key expired. Please renew the API key."
details: reason = API_KEY_INVALID  (generativelanguage.googleapis.com)

ここで注目したいのは、message が「expired(期限切れ)」と言っているのに、reason は API_KEY_INVALID(無効なキー)だという点です。公式の API キーのページを読み返しても、標準の鍵に有効期限が設けられているという記述は私には見つけられませんでした。

つまり、手元の症状を最も正確に表しているのは reason のほうで、「サーバーが、いま渡されたその文字列を有効な鍵として受け取れなかった」と読むのが安全です。渡した鍵が悪いのか、渡されたものが想定と違うのか。疑う入口はこの二つに割れます。

疑う順番は「渡されたもの」が先

鍵そのものを疑う前に、そもそも ADK に何が渡っているかを確かめます。理由は単純で、鍵を作り直しても、渡る経路が変わらなければ結果が変わらないからです。

公式のページには、クライアントライブラリは GEMINI_API_KEY または GOOGLE_API_KEY を読み、両方あるときは GOOGLE_API_KEY が優先される、と書かれています。ADK の公式ドキュメントが案内している設定は、エージェントのフォルダに置く .env に GOOGLE_API_KEY を書く形です。

ここに落とし穴が一つあります。シェルのほうに、以前の鍵が GOOGLE_API_KEY として残っていたらどうなるでしょうか。.env に新しい鍵を書いたつもりでも、どちらが読まれているのか、見た目では判別できません。ADK が .env の値をどの優先順位で読み込むかは、公式ページには記載がありませんでした。ですから私は「たぶんこちらだろう」で進めず、実際に調べる側に回ります。

鍵の文字列を出さずに、出どころだけを照らす

鍵を画面やログに貼るのは避けたいので、末尾 4 文字だけを出すスクリプトを使います。シェルの環境変数と、.env ファイルの中身を並べて見ます。

import os
import sys
from pathlib import Path
 
 
def tail(value):
    """鍵の末尾 4 文字だけ返す。全体は絶対に出力しない。"""
    if not value:
        return "(未設定)"
    value = value.strip().strip('"').strip("'")
    return f"…{value[-4:]} (長さ {len(value)})"
 
 
def read_dotenv(path):
    result = {}
    if not path.exists():
        return result
    for line in path.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#") or "=" not in line:
            continue
        key, _, val = line.partition("=")
        result[key.strip()] = val
    return result
 
 
agent_dir = Path(sys.argv[1] if len(sys.argv) > 1 else ".")
env_file = read_dotenv(agent_dir / ".env")
 
print("シェル  GOOGLE_API_KEY :", tail(os.environ.get("GOOGLE_API_KEY")))
print("シェル  GEMINI_API_KEY :", tail(os.environ.get("GEMINI_API_KEY")))
print(".env    GOOGLE_API_KEY :", tail(env_file.get("GOOGLE_API_KEY")))
print(".env    GEMINI_API_KEY :", tail(env_file.get("GEMINI_API_KEY")))

実行は python3 probe_key.py ./my_agent のように、.env を置いたフォルダを引数に渡します。出力のうち、末尾 4 文字が AI Studio の画面で見えている鍵と一致しない行があれば、そこが古い鍵の居場所です。長さが想定と違うときは、貼り付け時に引用符や改行が混ざっている可能性が高くなります。

四行のうち、最近作った鍵の末尾と一致するものが一つもなければ、それは ADK の問題ではなく、貼った鍵そのものが違う、という意味になります。この切り分けだけで、半分の道が閉じます。

ADK を外して、鍵だけを REST で試す

次に、ADK と鍵を切り離します。同じ鍵で、モデル一覧を取る最小のリクエストを送ってみます。

# 鍵は環境変数から読み、コマンド履歴に残さない
curl -s -o /dev/null -w "%{http_code}\n" \
  -H "x-goog-api-key: ${GOOGLE_API_KEY}" \
  "https://generativelanguage.googleapis.com/v1beta/models"

200 が返れば、鍵は生きています。疑いは ADK 側の設定や、別の変数が読まれている経路に移ります。400 や 403 が返れば、鍵そのものの状態が問題です。この二分で、「どちらの箱を開けるか」が決まります。

鍵の状態に問題があるとき、公式のページから拾える候補は次のとおりです。

  • 制限のない(Unrestricted)標準の鍵は Gemini API に拒否されることがあり、しばらく使われていない制限なしの鍵は止められて「Blocked」と表示されます。新しい鍵を作るか、Gemini API に制限した鍵を使うことになります。
  • 他の Google API と共用している鍵に制限をかけた場合は、Gemini へのリクエストが失敗します。Gemini 用に別の鍵を作る形になります。
  • 画面に鍵が見えないときは、既存の Cloud プロジェクトを AI Studio に取り込む必要があります。

「期限切れ」という文言に引っ張られていた間は、鍵の制限と状態を見るという発想が出てきませんでした。reason を読み、状態の表を見るようにしました。順番が変わると、行き先も変わるのだと気づいたのは、何度か回り道をしたあとでした。

私が引いた線引き

この件で私が改めたのは、エラーを読む順番でした。長い間、メッセージの日本語訳や英文をそのまま原因として受け取り、鍵を作り直す方向へ走っていたのです。結果は芳しくありませんでした。いまは次の三段で止まります。

  1. 応答の reason を読みます(文面は参考にとどめます)
  2. 末尾 4 文字で、どの経路の鍵が渡っているかを確かめます
  3. ADK を外し、REST で鍵だけを試します

文面は参考、reason は証拠、鍵の作り直しは最後。 この一文だけは、疲れている夜でも守るようにしています。

次にやること

まずは、手元のエージェントのフォルダで上の 4 行出力を一度だけ取ってみてください。末尾 4 文字が見えるだけで、「どの鍵を疑うか」が決まります。個人開発で壁紙アプリや Web の運用をしていると、古い鍵がシェルの片隅に残る場面は珍しくありません。関連して、鍵の優先順位を CLI で追った記録は Gemini CLI に新しいキーを渡しても「API key not valid」。読まれていたのは三か所目の古いキーでした に、GOOGLE_API_KEY と GEMINI_API_KEY の取り違えは 環境変数の食い違いの記事 に、鍵の差し替えを止めずに行う手順は 無停止での鍵ローテーション にまとめています。

シェア

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

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

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

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

関連記事

◈ API / SDK2026-10-30
「API key expired」と出ても、期限切れとは限りません。キーを作り直す前に、実際に送られているキーを確かめる
Gemini API が 400 の API_KEY_INVALID を返しても、応答だけでは期限切れか別の原因かを区別できません。環境変数の優先順位と空白・引用符を手元で確かめる診断スクリプトを、ダミーキーで動かした結果とともに残します。
◈ API / SDK2026-10-14
config に「Extra inputs are not permitted」が出たら、キーの綴りを一つずつ疑います
google-genai SDK で config を渡した途端に pydantic の ValidationError(extra_forbidden)が出る原因は、ほぼ綴りの一字違いです。手元で再現した出力と、呼び出し前に怪しいキーを洗う関数、text が None になる場合の見分け方を書き残します。
◈ API / SDK2026-09-01
Gemini の API キーを差し替えても旧キーが勝つ。決め手は読み込み順ではありませんでした
同じ環境変数名を複数の経路が供給していると、キーを差し替えても古い値が残ります。読み込み順を四通り入れ替えた実測と、供給と読み取りを台帳に残す監査シムの実装をまとめました。