「自宅のMacBookでは普通に動いていた Gemini API のスクリプトが、月曜日に出社して会社支給のWindows機で動かそうとした瞬間にハングする」— これは私が実際にぶつかった問題で、原因にたどり着くまで丸一日溶かしました。エラーメッセージは SSLError: SSL: CERTIFICATE_VERIFY_FAILED だったり、何も返ってこないまま無言でタイムアウトしたりと一定しないので、初見ではどこから手を付ければいいか分かりにくいのです。
ここではGemini API が社内ネットワークや特殊なルーター環境から接続できないときに、どのレイヤーで何が起きているのかを切り分け、実際に動くまで持っていく手順を整理します。コード例は Python と Node.js の両方で示します。
接続できないときに最初に確認する3つのレイヤー
Gemini API への接続失敗は、ほとんどの場合 (1) DNS / ネットワーク到達性、(2) HTTP プロキシ、(3) TLS 証明書 の3層のいずれかで起きています。エラーメッセージを読む前に、まず curl で物理的な疎通を確認するのが回り道のようでいて一番速いです。
# (1) DNSと到達性の確認
curl -v https://generativelanguage.googleapis.com/v1beta/models -m 10
# (2) プロキシ経由でアクセスできるか
curl -v -x http://proxy.example.com:8080 https://generativelanguage.googleapis.com/v1beta/models -m 10
# (3) 証明書チェーンを表示
openssl s_client -connect generativelanguage.googleapis.com:443 -showcerts < /dev/null 2>&1 | head -30もし (1) で Could not resolve host が出るなら DNS の問題、Connection timed out ならファイアウォール、SSL certificate problem なら証明書の問題、というように、最低限ここで層を絞り込んでから次に進みます。Pythonアプリ側で延々とログを増やすより、まず素のHTTP層で何が起きているか確かめるのが原則です。
HTTP_PROXY / HTTPS_PROXY 環境変数の落とし穴
社内ネットワークからの接続では、ほぼ必ずプロキシを経由します。google-genai をはじめ多くのSDKは、内部的に標準的なプロキシ環境変数を読みに行く設計です。ただしここに細かい落とし穴がいくつかあります。
第一に、HTTPS_PROXY の値も http:// で始めるのが基本です。https://proxy.example.com:8080 と書いて延々と接続できずに悩んだケースを何度か見ました。プロキシサーバーへの接続自体は平文HTTPで張り、その上で目的サイトへのHTTPSトンネルを CONNECT する仕組みなので、この指定で正しいのです。
第二に、大文字と小文字の両方を設定すること。Linuxの一部ライブラリは http_proxy(小文字)しか見ません。
export HTTP_PROXY="http://user:pass@proxy.example.com:8080"
export HTTPS_PROXY="http://user:pass@proxy.example.com:8080"
export http_proxy="$HTTP_PROXY"
export https_proxy="$HTTPS_PROXY"
export NO_PROXY="localhost,127.0.0.1,.internal.corp"第三に、パスワードに記号が含まれる場合はURLエンコードすること。@ や # をそのまま入れると、認証文字列の解析が壊れて「プロキシに繋がらない」のではなく「謎の認証エラー」として表面化します。Pythonなら urllib.parse.quote(password, safe="") で素直にエンコードしましょう。
なお NO_PROXY に社内ホストを並べておかないと、社内のローカルAPIまでプロキシ経由で出ようとして二度手間になります。地味ですが効きます。
SSL証明書エラーへの正しい対処(自己署名証明書を入れる)
一番悩みやすいのが SSL検証エラーです。多くの企業ネットワークでは、プロキシが TLS を一旦終端して再暗号化する MITM プロキシが入っており、そのプロキシの自己署名証明書がOSの信頼ストアに入っていないと CERTIFICATE_VERIFY_FAILED が起きます。
ここで絶対にやってはいけないのが、verify=False で検証を無効化することです。一見動いてしまうので楽ですが、社内プロキシのなりすましどころか、外部ネットワークでも盗聴・改ざんを許す状態になります。本番に持ち込まれて事故になりがちな最悪のパターンです。
正しい対処は、社内プロキシの証明書(情シスから .pem または .crt で配布されているはず)をPython/Node.jsの信頼バンドルに追加することです。Pythonなら以下のように環境変数で指定するのが最も汎用性が高い書き方です。
# 会社配布の証明書を信頼ストアに登録
export REQUESTS_CA_BUNDLE=/path/to/corporate-ca.pem
export SSL_CERT_FILE=/path/to/corporate-ca.pem
# certifi を使うアプリには certifi のバンドルに追記する手もある
python -c "import certifi; print(certifi.where())"
# 出力されたパスに corporate-ca.pem の内容を追記Node.js の場合は NODE_EXTRA_CA_CERTS=/path/to/corporate-ca.pem を環境変数に設定するだけで、fetch も https.request も両方読みに行きます。google-genai の Node SDK もこれで素直に通ります。
google-genai SDK でプロキシを通す具体的なコード
Python の google-genai は内部で httpx を使っているので、プロキシ環境変数を自動で拾います。ただし明示的にコードで指定したい場合(複数の出口を切り替えたい等)は、HTTPクライアントを差し込む形になります。
# pip install google-genai httpx
import os
import httpx
from google import genai
# 認証付きプロキシをコードで明示指定する例
proxy_url = "http://user:pass@proxy.example.com:8080"
http_client = httpx.Client(
proxy=proxy_url,
verify=os.environ.get("REQUESTS_CA_BUNDLE", True),
timeout=30.0,
)
client = genai.Client(
api_key=os.environ["GEMINI_API_KEY"],
http_options={"client_args": {"transport": httpx.HTTPTransport(proxy=proxy_url)}},
)
response = client.models.generate_content(
model="gemini-2.5-flash",
contents="社内ネットワークから接続テストです。",
)
print(response.text)
# 期待出力: "接続テストを受信しました。..." のような短文応答Node.js では undici の ProxyAgent を setGlobalDispatcher で差し込むのが、@google/genai のような fetch ベースのSDKに対して最も素直に効きます。
// npm install @google/genai undici
import { GoogleGenAI } from "@google/genai";
import { ProxyAgent, setGlobalDispatcher } from "undici";
setGlobalDispatcher(new ProxyAgent("http://user:pass@proxy.example.com:8080"));
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
const result = await ai.models.generateContent({
model: "gemini-2.5-flash",
contents: "社内ネットワークから接続テストです。",
});
console.log(result.text);
// 期待出力: 短文の応答テキスト社内CAの追加は前述の NODE_EXTRA_CA_CERTS で済むので、コード側はプロキシ指定だけに集中できます。
それでも繋がらないときのチェックリスト
ここまでやって動かない場合、原因はもう少し珍しい場所に潜んでいます。私が過去に踏んだものを優先順にいくつか挙げます。
まず疑うのはファイアウォールでドメイン単位ではなくIP単位の許可リストになっているケースです。generativelanguage.googleapis.com の背後IPは Google のフロントエンドで頻繁に変わるため、IP固定の許可ルールは早晩破綻します。情シスにはドメインまたは Google ASN ベースでの許可をお願いするのが筋です。
次に多いのが認証プロキシのSession Tokenが切れているケース。WebブラウザではSSOで透過的に通るのに、CLIから叩くと 407 Proxy Authentication Required が返るのは大体これです。NTLM認証なら cntlm のような認証ブリッジを挟むのが定番の解です。
地味な落とし穴として、pip install 自体がプロキシを通れていないことも少なくありません。pip --proxy http://... で明示するか、~/.pip/pip.conf に [global] proxy = ... を書くと安定します。SDKを取りに行けないと、いくらコードを直しても動きようがないですからね。
最後に、本格的に切り分けるなら、社内ネットワークと自宅ネットワークの差分を取りたくなります。
関連する記事として、Gemini API の認証エラーをパターン別に解決する手順 と 503 Service Unavailable が頻発するときの切り分け も合わせて読むと、ネットワーク以外の原因まで一通り潰せます。
社内ネットワークまわりは「動かない理由が複層になっている」ことが多く、一発で原因を当てるのは難しいです。curl → 環境変数 → 証明書 → SDK の順で1つずつ層を確定させていけば、たいていは半日以内に出口にたどり着けます。今日のあなたのデバッグが、もう少し早く終わりますように。