Claude Media
AnthropicのPython SDKでプロキシ環境変数が反映されない問題を解決する

AnthropicのPython SDKでプロキシ環境変数が反映されない問題を解決する

企業プロキシ環境でAnthropicのPython SDKがAPIConnectionErrorを返す既知の不具合と、現行バージョンの自動検出の仕組み・明示設定の方法を解説します。

AnthropicのPython SDKで起きるプロキシ関連のAPIConnectionError

企業ネットワーク配下でAnthropicのPython SDKを使うと、http_proxyhttps_proxyを設定していてもanthropic.APIConnectionError: Connection error.が発生することがあります。SDKがプロキシ環境変数を読み込まず、社内ネットワークを経由せず直接インターネットへ接続しようとして失敗するためです。

APIConnectionErrorはネットワーク到達不能を示すSDK共通の例外クラスです。DNS解決の失敗やTLSハンドシェイクの失敗もこのクラスで表現されますが、プロキシ未適用もその一因になります。実際にGitHub issue #923では、anthropic==0.49.0httpx==0.27.0の組み合わせでhttp_proxy/https_proxyを設定してもSDKの接続に反映されないと報告されています。

v0.47.0〜v0.53.xでプロキシ環境変数が無視されていた理由

原因はSDK側が持つカスタムトランスポートでした。SDKはidleタイムアウトを避けるためTCPのkeep-alive挙動を細かく制御しており、そのために内部でhttpx.HTTPTransportを独自に組み立てています。

このカスタムトランスポートを渡すと、httpx自身が持つ「環境変数からプロキシを自動検出する」機能が無効になります。関連issue#878は、v0.46.0では問題なく動いていたのにv0.47.0へ上げたらhttps_proxyが効かなくなったと報告しています。トランスポートの組み立て方が変わった時期と一致する症状です。

つまり、httpx単体なら動くはずのhttp_proxy/https_proxyが、SDKの内部実装との競合で無視される状態が半年近く続いていたことになります。

v0.54.0の修正内容 — 独自のプロキシ検出ロジックを追加

Anthropicはこの競合をPR #969で修正し、v0.54.0(2025年6月10日リリース)に取り込みました。修正の核は新設された_utils/_httpx.pyget_environment_proxies()関数です。

この関数は標準ライブラリのurllib.request.getproxies()でプロキシ設定を取得し、httphttpsallの各スキームに対応するマウント先と、no_proxyで除外するホストのリストを作ります。SDKはこの結果をもとにhttpx.HTTPTransportを個別のマウントとして組み立て直し、環境変数のプロキシ設定を独自トランスポートと共存させています。

issue #923へのコメントでAnthropicのメンテナーは「v0.54.0を試してほしい。httpのプロキシ環境変数サポートを意図せず外していたのを戻した」と回答しました。ユーザー側のコードを変更しなくても、SDKをアップグレードするだけで直る不具合だったことになります。issue報告者自身が回避策としてhttpx.Clientを自作しhttp_client引数に渡す方法を提示していましたが、v0.54.0以降はその回避策なしでも動くようになりました。

現在のバージョンでもこの自動検出は生きている

SDKはv1.0.0(2026年8月20日リリース)でHTTPバックエンドをhttpxから、API互換のフォークであるhttpx2へ移行しました。破壊的変更を伴う移行でしたが、v0.54.0で追加されたプロキシ自動検出のロジックは、この移行後も同じ形で残っています。

現行のmainブランチをPyPI最新版のv1.6.0に合わせて確認すると、_utils/_httpx.pyget_environment_proxies()v0.54.0のときと同一です。SDKが自前でhttpx2クライアントを組み立てる箇所でこの関数を呼び出す構造も変わっていません。

バージョンプロキシ環境変数の状態
v0.46.0以前プロキシ環境変数の状態機能する
v0.47.0〜v0.53.xプロキシ環境変数の状態独自トランスポートとの競合で無視される
v0.54.0(2025-06-10)プロキシ環境変数の状態get_environment_proxies()の追加で修正
v1.0.0(2026-08-20)プロキシ環境変数の状態HTTPバックエンドがhttpx2へ移行。修正内容は継続
v1.6.0(現行最新)プロキシ環境変数の状態同じロジックが動作中

この自動検出が働くのは、SDKが自前でDefaultHttpxClientを組み立てるとき、つまりhttp_client引数を渡さずにAnthropic()を初期化した場合に限られます。

AnthropicのAPIエンドポイントは常にTLSでの接続になるため、実務上重要になるのはhttps_proxy(またはHTTPS_PROXY)です。http_proxyだけを設定していても、API呼び出し自体には影響しません。この不具合はトランスポート層で起きるため、通常のメッセージ作成だけでなくストリーミングやMessage Batches、tool_runnerを使った呼び出しでも同じAPIConnectionErrorが発生します。エンドポイントごとに個別対応する必要はありません。

verify・certの設定はプロキシ経由の接続にも引き継がれる

_base_client.pyの実装を見ると、プロキシ用のマウントを作る際にverifycerttrust_envhttp1http2limitsの各引数を、通常のトランスポートと同じ値で渡しています。

社内CA証明書を使う自己署名プロキシ環境では、DefaultHttpxClient(proxy=..., verify="/path/to/ca-bundle.pem")のようにverifyを指定すれば、その証明書検証はプロキシ経由の接続にも適用されます。プロキシ設定だけ通っても証明書エラーで止まる場合は、このverify引数を疑うのが近道です。

ANTHROPIC_BASE_URLという環境変数も存在しますが、これはAPIの接続先URLそのものを差し替えるためのもので、プロキシとは別の仕組みです。自前のゲートウェイを経由させたい場合はこちらを使い、企業プロキシ経由でapi.anthropic.comへ到達したいだけの場合はプロキシ環境変数の話に限定して考えます。

NO_PROXYで特定ホストだけプロキシを迂回する

get_environment_proxies()no_proxy環境変数もそのまま解釈します。値が*ならプロキシ検出自体を無効にし、個別のホスト名を指定すればそのホストだけ直接接続に切り替わります。

ホスト名がIPv4・IPv6アドレスやlocalhostの場合は完全一致でマウントがNoneになり、それ以外の文字列は末尾一致のパターンで除外されます。社内APIサーバーなど、Anthropic以外の宛先だけプロキシを迂回させたい場合は、no_proxyにそのホスト名をカンマ区切りで列挙すれば動作します。

http_clientを自分で渡すときはプロキシも明示する

http_client引数に自分で作ったhttpx2.Clientを渡すと、SDKの自動検出ロジックは丸ごと迂回されます。プロキシが必要な環境で独自のhttp_clientを使うなら、DefaultHttpxClientproxyを明示します。

import httpx2
from anthropic import Anthropic, DefaultHttpxClient
 
client = Anthropic(
    http_client=DefaultHttpxClient(
        proxy="http://my.proxy.example.com:8080",
        transport=httpx2.HTTPTransport(local_address="0.0.0.0"),
    ),
)

生のhttpx2.ClientではなくDefaultHttpxClientを使うのは、SDKが前提とするデフォルトのタイムアウトや接続数上限を保つためです。素のhttpx2.Clientを渡すとこれらの既定値が失われます。

非同期クライアントではAsyncAnthropicDefaultAsyncHttpxClientの組み合わせが同じパターンに対応します。

import httpx2
from anthropic import AsyncAnthropic, DefaultAsyncHttpxClient
 
client = AsyncAnthropic(
    http_client=DefaultAsyncHttpxClient(
        proxy="http://my.proxy.example.com:8080",
    ),
)

同期・非同期どちらを選ぶかは並列度の要件で決まる話で、プロキシ設定の考え方自体は共通です。実装の違いやaiohttpバックエンドとの使い分けはClaudeのPython SDKで非同期実行とtool_runnerを実装するで扱っています。

動作確認の手順とチェックリスト

自分の環境がこの不具合に当たるかどうかは、まずSDKのバージョンを確認します。

python -c "import anthropic; print(anthropic.__version__)"

0.54.0未満であれば、アップグレードだけで解消する可能性が高い状況です。バージョンが十分に新しいのにエラーが続く場合は、実際にプロキシがマウントされているかをコードで確認します。

pip install --upgrade anthropic
export HTTPS_PROXY="http://my.proxy.example.com:8080"
python -c "
from anthropic import Anthropic
client = Anthropic()
print(client._client._mounts)
"

_mountshttps://のマウントが表示されれば、環境変数のプロキシがSDK内部の接続に反映されています。空の辞書のままなら、下の表で該当する状況を確認します。

認証が必要な社内プロキシでは、proxy="http://user:password@my.proxy.example.com:8080"のようにURLへ認証情報を埋め込む書式がそのまま使えます。httpx2はhttpxとAPI互換のフォークなので、環境変数側でも同じ書式が有効です。

状況対処
anthropic.__version__が0.54.0未満対処pip install --upgrade anthropicでv0.54.0以上に上げる
http_clientを渡さずAnthropic()を初期化している対処環境変数のプロキシが自動検出される。追加設定は不要
http_clientに自作のhttpx2.Clientを渡している対処DefaultHttpxClientproxy引数で明示する
NO_PROXY=*を設定している対処プロキシ自動検出そのものが無効化される仕様どおりの挙動
Dockerイメージやrequirements.txtでバージョンをピン留めしている対処ピン留めを外すかv0.54.0以上を明示指定する

古いDockerイメージやバージョンのピン留めがこの不具合を今も再発させる

v0.54.0のリリースからすでに1年以上が経ち、現行のPyPI最新版はv1.6.0です。それでもrequirements.txtanthropic==0.49.0のようにバージョンをピン留めしたままのプロジェクトや、ビルドキャッシュを使い回すDockerイメージでは、この不具合が今も再現します。

依存関係のロックファイルを使うプロジェクトでは、anthropic本体を直接ピン留めしていなくても、他のパッケージが古いanthropicを間接的に要求してロックされたままになっているケースもあります。ロックファイルの更新頻度が低いリポジトリほど、この不具合に当たる確率が上がります。

APIConnectionErrorのメッセージ自体はプロキシに触れないため、タイムアウトやDNSの問題と見分けがつきにくく、原因の切り分けに時間がかかりやすい不具合です。他のAPIErrorサブクラス(RateLimitErrorAPIStatusErrorなど)との違いはClaude APIのエラー形式とSDK例外クラスの言語別対応表にまとめています。

v1.0.0のhttpx2移行はSDKの破壊的変更を伴うため、0.x系から上げる際は移行ガイドの確認が前提になります。移行の実務手順は/claude-api upgradeでPython SDKをv0.xからv1へ移行するで扱っています。

本記事で確認したのはAnthropicAsyncAnthropic(Direct API接続)のクライアントです。Bedrock・Vertex・AWS向けの各クライアントも同じ_base_client.pyを継承していますが、個別の動作検証はしていません。

まとめ

AnthropicのPython SDKでhttp_proxy/https_proxyが効かない場合、まずanthropic.__version__を確認します。v0.54.0以降ならSDKが環境変数のプロキシを自動検出しますが、http_clientを自分で渡すとその検出は働きません。その場合はDefaultHttpxClient(proxy=...)で明示します。古いバージョンを使い続けているプロジェクトでは、アップグレードが最短の解決策です。バージョン確認と_mountsの目視、この2手順だけで切り分けが完結します。

この記事を共有:XはてブLinkedIn