# OpenAI API 接続エラー: APIConnectionError はまず経路から切り分ける

> APIConnectionErrorが出たら、失敗したプロセスで接続先、例外の原因、HTTP応答の有無を確認します。原因に合うCA・プロキシ・通信許可を直し、同じ条件の小さい要求から復旧を確かめます。リクエストIDがなくても、未処理や未課金とは断定できません。

- URL: https://blog.laozhang.ai/ja/posts/openai-api-error-connection-error
- Published: 2026-05-06
- Updated: 2026-10-07
- Author: LaoZhang AI Team (https://blog.laozhang.ai/ja/about)
- Topic: API ガイド
- Tags: OpenAI API, APIConnectionError, 接続エラー, SDK, API エラー

---
`openai.APIConnectionError: Connection error.` が出たら、**失敗したアプリと同じプロセスで、実際の接続先と元の例外を確認してください。** DNS、TLSの証明書検証、プロキシ、外向き通信の許可に問題があれば、その設定を直します。HTTPの401や429が返っている場合は、認証や利用枠の確認へ進みます。エラー名だけを見てAPIキーを作り直すより、この分岐を先に確かめるほうが修正先を絞れます。

`APIConnectionError` は、SDKが接続や通信に失敗したときの例外です。[OpenAIの公式エラーガイド](https://developers.openai.com/api/docs/guides/error-codes)は、ネットワーク、プロキシ、SSL証明書、ファイアウォール、コンテナの権限を確認するよう案内しています。ただし、応答やリクエストIDが手元にないことは、サーバーが要求を受け取っていない証明にはなりません。送信後に応答を失った場合もあるため、再送の判断は切り分けと分けて行います。

## 最初の切り分け：HTTP応答があるかを確かめる

最初に残すのは、発生時刻、接続先のホスト、例外名、HTTPステータスの有無、取得できたリクエストIDです。接続先は設定ファイルのつもりではなく、**失敗したクライアントが実際に使っている値**を確認します。APIキー、認証ヘッダー、プロンプト全文をログに出す必要はありません。

| 確認できたもの | 次に調べること | 最初の対応 |
| --- | --- | --- |
| `APIConnectionError`、HTTP応答は取得できない | 元の例外、実際の接続先、DNS・TLS・プロキシ・外向き通信 | 同じプロセスの設定を保って原因を記録する |
| Pythonの`APITimeoutError`、Nodeの`APIConnectionTimeoutError` | 接続前なのか、送信・応答待ちなのか、処理全体の期限 | タイムアウトの種類と経過時間を確認する |
| HTTP 401 | 接続先とキーの対応、キーの権限、組織・プロジェクト | 正しい提供元の認証設定を確認する |
| HTTP 429 | 応答本文の詳細コード、送信量または課金・利用枠 | 原因を分類してから待機や設定変更を判断する |
| HTTP 500／503 | 応答本文、リクエストID、提供元の障害情報 | 一時的な失敗かを確認し、上限付きで再試行する |
| ストリームの途中で切れた | 受信済みの内容、切れた時点の例外、処理済みの副作用 | 完了扱いを止め、最初から自動再送しない |

Pythonでは、応答の4xx／5xxは `APIStatusError` 系の例外で、`status_code` と `response` を確認できます。タイムアウトは `APITimeoutError` で、`APIConnectionError` の派生です。Nodeでは接続タイムアウトが `APIConnectionTimeoutError` になります。分類は2026年10月6日に確認した[Pythonリファレンス](https://developers.openai.com/api/reference/python)と[TypeScriptリファレンス](https://developers.openai.com/api/reference/typescript)に基づきます。独自のHTTPクライアントやフックが投げた例外は、そのまま伝わる場合もあります。

429が返ったら、[送信量によるレート制限の切り分け](https://blog.laozhang.ai/ja/posts/openai-api-rate-limit)を使います。本文に `insufficient_quota` や課金関連の詳細コードがあれば、[残高・支出上限・承認済み利用枠の確認](https://blog.laozhang.ai/ja/posts/openai-api-quota-exceeded-error)へ進んでください。接続エラーの再試行だけでは、これらの設定は直りません。

## ブラウザではなく、失敗したプロセスで調べる

ブラウザでOpenAIのサイトを開けても、Pythonの証明書ストア、Nodeの `fetch`、コンテナの外向き通信が同じとは限りません。ローカルで成功し、本番だけ失敗する場合は、本番のコンテナや関数、リージョン、クライアント設定を対象にします。

比較する項目は、接続先のホストとAPIのパス、SDK・HTTPライブラリのバージョン、プロキシの使用有無、信頼するCA、接続・読み取りのタイムアウト、再試行回数です。キーの値を並べる代わりに、キーの管理名や所属プロジェクトが一致するかを確認します。プロキシURLに認証情報がある場合も、その値を公開ログへ出さないでください。

### Python：既存クライアントの例外を同じ場所で捕捉する

次の関数は、既存アプリの**非ストリーミングの操作を1回実行するための診断用部品**です。クライアントを別に作り直さず、既存のHTTP設定を使った操作を渡します。タイムアウトを先に捕捉し、元の例外の型を `__cause__` からたどります。戻り値の記録には応答本文や秘密値を入れません。

```python
import time
import uuid
import openai


def cause_types(error):
    names = []
    seen = set()
    current = error.__cause__
    while current is not None and id(current) not in seen:
        seen.add(id(current))
        names.append(type(current).__name__)
        current = current.__cause__
    return names


def diagnose_once(operation):
    client_request_id = "diag-" + uuid.uuid4().hex
    started = time.monotonic()
    record = {"client_request_id": client_request_id}
    result = None
    try:
        result = operation(client_request_id)
        record.update(
            kind="response",
            request_id=getattr(result, "_request_id", None),
        )
    except openai.APITimeoutError as error:
        record.update(kind="timeout", causes=cause_types(error))
    except openai.APIConnectionError as error:
        record.update(kind="connection", causes=cause_types(error))
    except openai.APIStatusError as error:
        record.update(
            kind="http_error",
            status=error.status_code,
            request_id=error.request_id,
        )
    record["elapsed_seconds"] = round(time.monotonic() - started, 3)
    return result, record
```

呼び出し部分は、既存の `client` と、そのプロジェクトで利用可能な `model_id` を使って次のように組み込みます。両変数はアプリ側で準備済みであることが前提です。**これは実際の生成要求で、成功すれば通常のAPI利用料金が発生し得ます。** 実行前に接続先と再送の可否を確認してください。

```python
result, record = diagnose_once(
    lambda client_request_id: client.with_options(
        max_retries=0,
        timeout=30.0,
    ).responses.create(
        model=model_id,
        input="Reply with OK.",
        extra_headers={"X-Client-Request-Id": client_request_id},
    )
)
print(record)
```

`max_retries=0` は診断中の送信回数を分かりやすくする設定です。30秒はこの小さい確認要求の例で、長い生成に共通する推奨値ではありません。Pythonの数値タイムアウトは秒単位です。`with_options` で既存クライアントの接続設定を保ち、要求ごとに再試行と期限を指定する方法は[公式Pythonリファレンス](https://developers.openai.com/api/reference/python)を参照してください。

`kind=connection` なら `causes` に出た例外の型と、社内で安全に扱える元のエラー詳細を照合します。たとえば名前解決、証明書検証、プロキシ接続のどこで失敗したかが分かれば、次節の対応へ進めます。型名だけで原因が分からない場合は、タイムスタンプをネットワークやプロキシのログと合わせます。`kind=response` はこの1件の応答を取得したという意味で、元の大量処理まで復旧した証明ではありません。

### curlは同じ環境の経路確認に使う

コンテナ内などで、認証なしのHTTPS応答を確かめる補助確認にはcurlを使えます。OpenAIへ直接接続する場合の例は次のとおりです。Azureやゲートウェイを使っている場合は、提供元が許可する確認用URLに変更します。未知のホストへキーを送らないでください。

```bash
TARGET_URL='https://api.openai.com/v1/models'
curl -q --silent --show-error \
  --connect-timeout 5 --max-time 15 \
  --output /dev/null \
  --write-out 'http=%{http_code} dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} total=%{time_total}\n' \
  "$TARGET_URL"
curl_exit=$?
printf 'curl_exit=%s\n' "$curl_exit"
```

`-q` はcurlの最初の引数に置き、既定のcurl設定ファイルを読み込ませません。プロキシの環境変数は無効にしないため、実際にどの経路を使うかは確認が必要です。このコマンドはTLS検証を維持し、APIキーも生成要求も送信しません。`--connect-timeout` は名前解決と接続・TLS確立を含む段階、`--max-time` は全体の上限です。[curlの公式マニュアル](https://curl.se/docs/manpage.html)で各オプションと終了コードを確認できます。

| 結果 | 読み取り方と次の確認 |
| --- | --- |
| 終了コード5／6 | プロキシ／接続先の名前解決に失敗。実行環境のDNSとホスト名を確認する |
| 7 | 接続を確立できない。接続先、ポート、外向き通信、プロキシ側の許可を確認する |
| 35／60／77 | TLS接続、証明書の信頼、CAファイルに関する失敗。エラー詳細とCA設定を照合する |
| 28 | 時間切れ。出力の時刻情報とログから、接続段階かその後かを調べる |
| 52／56／97 | 空の応答、受信失敗、プロキシのハンドシェイク失敗。途中の装置や提供元のログと照合する |
| HTTP 401などを取得 | HTTPS上で何らかのHTTP応答を取得。接続先からの応答か、プロキシ自身の応答かも確認する |

HTTPステータスとcurlの終了コードは別です。この例では `--fail` を使わないため、401や503でもcurlが終了コード0を返すことがあります。`http=000` は確認中にHTTPステータスを得られなかったという意味で、元の生成要求が未処理だった証拠ではありません。

また、curlが成功してSDKが失敗するなら、SDKのCA・プロキシ・HTTP実装を比較します。curlの確認だけでは、アプリの認証、モデルへのアクセス、生成成功は確認できません。

![失敗したプロセスの接続先、原因例外、CA、プロキシ、外向き通信を確かめ、curlとSDKの結果を区別する図](https://blog.laozhang.ai/posts/ja/openai-api-error-connection-error/img/explainer-1.webp)

## 原因に合った設定を直す

### 社内ネットワークで証明書検証に失敗する

社内のHTTPS検査プロキシがある場合、ブラウザが信頼する会社のCAを、PythonやNodeのHTTPクライアントが信頼していないことがあります。まず、表示された証明書の発行者と会社のネットワーク構成を担当者に確認します。会社が指定したCAファイルと設定方法を入手し、**実際に失敗したHTTPクライアントの信頼設定へ追加**してください。

日本語の[Qiita記事「OpenAI API利用時のSSLErrorに対して証明書をダウンロードして解決する」](https://qiita.com/pm00/items/9983bac9f188e73cda20)は、業務PCのプロキシと証明書検証の具体例を扱っています。ただし、2023年公開・2025年更新の手順に出てくるcertifiの直接編集や `REQUESTS_CA_BUNDLE` を、現在のOpenAI SDKへそのまま当てはめないでください。requests向けの設定と、現在のSDKが使うHTTPライブラリの設定は区別が必要です。

2026年10月6日に確認した[Pythonリファレンス](https://developers.openai.com/api/reference/python)では、HTTPX2と `DefaultHttpx2Client` を使う構成が案内されています。インストール済みの旧版がHTTPXを使う場合は、その版の対応するクライアント設定を使います。現在の構成なら、会社指定CAを読み込んだ検証有効の `SSLContext` を用意し、対応するHTTPクライアントの `verify` に渡す方法があります。ファイルの存在、コンテナからの読み取り権限、証明書の更新状態も確認します。

検証を無効にする、ブラウザから取った証明書を根拠なく信頼する、SDKのインストール先を直接書き換える、といった対応は避けます。修正後、同じプロセスで証明書検証が成功し、小さいAPI要求の応答が取得できることを確認すれば、変更したCA設定の効果を判断できます。

### プロキシが必要なのに、SDKだけ通らない

端末のプロキシ設定や `HTTPS_PROXY` が、すべてのHTTP実装に同じように引き継がれるとは限りません。まず実際のクライアントが、会社指定のプロキシを使っているかを確認します。必要なら、そのSDK版とHTTPライブラリが対応する公開の設定方法でプロキシを指定します。

Nodeの場合は、**プロキシ設定と `fetch` 実装の組み合わせ**が重要です。[現行のTypeScriptリファレンス](https://developers.openai.com/api/reference/typescript)のNode例は、undiciの `fetch` と `ProxyAgent` を組み合わせ、対応する `fetchOptions` の `dispatcher` を渡します。別の `fetch` にundici専用の `dispatcher` だけを付けても、その設定を扱えるとは限りません。SDKに独自 `fetch` を渡しているなら、その実装を含めて確認してください。

Bunでは `proxy`、Denoでは `createHttpClient` とクライアントを使う構成など、実行環境で方法が異なります。古い記事の `httpAgent` をどの環境にも共通の修正として貼り付けず、実行中の環境とSDK版に対応する方法を選びます。認証付きプロキシは認証失敗や接続許可も確認し、通信禁止や地域制限を別経路で回避する対応にはしません。

### 本番コンテナだけ失敗する

同じイメージでも、実行先のDNS、CAファイル、外向き通信のルール、NATやプロキシ設定は異なります。起動したコンテナの中で接続先を確認し、ネットワーク担当者へ発生時刻と宛先ホスト・ポートを伝えます。名前解決が失敗したなら実行環境のDNSを、接続が拒否されたなら許可済み宛先への443番通信や指定プロキシへの経路を修正します。

許可変更が必要なら、管理者の承認された設定で行います。IPアドレスの固定やDNSの強制上書きで一時的に通しても、接続先の証明書や運用上の許可を確認できるとは限りません。修復後は、本番と同じプロセス・リージョンで確認を繰り返します。

### Azureやゲートウェイへ送っている

OpenAI互換のSDKを使っていても、通信先が `api.openai.com` とは限りません。Azure OpenAIなら対象リソースのエンドポイント、デプロイ、APIバージョンと、そのリソースのネットワーク設定を確認します。他社ゲートウェイなら、その提供元の接続先・キー・障害情報を使います。

OpenAI Statusが正常でも、別の提供元や自分の通信経路が正常とは限りません。[OpenAI Status](https://status.openai.com/)は、OpenAIへ直接接続している要求の発生時間帯を照合する資料として使います。過去の正常表示を、現在の障害の否定材料にはしません。ブラウザからの呼び出しだけで失敗する場合は、バックエンドの接続診断に加えてブラウザのネットワークエラーやCORSの表示を確認し、秘密のAPIキーをクライアント側へ配布しない設計にします。

## 再試行とタイムアウトを、処理全体の期限に合わせる

現在のPython・Node SDKは、対象の接続エラーや408、409、429、500以上のエラーを、既定で2回再試行します。Pythonは `max_retries`、Nodeは `maxRetries` で変更できます。ただし、再送できるリクエスト本文などの条件があり、すべての例外や処理が同じように再試行されるわけではありません。[Python](https://developers.openai.com/api/reference/python)・[TypeScript](https://developers.openai.com/api/reference/typescript)の説明を、実際のSDK版と照合してください。

診断中は再試行を0にして最初の失敗を見やすくし、復旧後に必要な上限を戻します。アプリの外側でもワーカーやキューが再送するなら、SDKと合わせた最大回数を数えます。CA不足、間違った接続先、拒否されたプロキシは、回数を増やしても修復できません。

タイムアウトの既定値は両SDKとも10分ですが、**Pythonの数値は秒、Nodeはミリ秒**です。Pythonの `timeout=30.0` とNodeの `timeout: 30_000` が同じ30秒です。Pythonの現行HTTPX2構成では `httpx2.Timeout` で接続・読み取り・書き込みなどを分けて指定できます。旧版のHTTPXへ、HTTPX2の名前をそのまま持ち込まないでください。[各SDKのタイムアウト説明](https://developers.openai.com/api/reference/python)を見て、外側のHTTPサーバー、関数、ジョブの期限も含めて設定します。

接続の段階で失敗しているなら、長い読み取り時間を増やすより接続設定を直します。接続後の長い生成で読み取りが時間切れになるなら、必要な出力量と処理時間を見直し、アプリ全体の期限に収まる範囲で延長を判断します。外側が先に終了する場合は、SDKの期限だけを延ばしても利用者へ結果を返せません。

![SDKと外側の再試行・タイムアウトを合算し、途中で切れたストリームを未完了として照合する図](https://blog.laozhang.ai/posts/ja/openai-api-error-connection-error/img/explainer-2.webp)

### ストリーミングの途中で切れた場合

ストリームが返った時点と、最後まで読み終えた時点は違います。例外の捕捉は、要求を開始する箇所だけでなく、受信イベントを読むループまで含めます。途中のテキストは未完了として扱い、完了イベントや正常な読み取り終了を確認してから成功にします。

現行のPython SDKでは、`Stream`／`AsyncStream` を読む途中のタイムアウトは `APITimeoutError`、ほかのHTTP要求の失敗は `APIConnectionError` として扱われます。**受信途中のストリームは自動的に最初から再生されません。** 旧来のAssistantsや `with_streaming_response` の扱いまで同一とは限らないため、使っている方式を[公式Pythonリファレンス](https://developers.openai.com/api/reference/python)で確認してください。

途中の出力を保存し、完了状態とエラーを分けて記録します。ツール呼び出しなどで外部への操作を済ませているなら、再要求による重複実行も確認します。最初から再送する場合は、何を再実行してよいかをアプリ側で決め、部分出力を完成した回答として重ねて表示しないようにします。キャンセルしても、サーバー処理や課金が取り消された証明にはなりません。

## 復旧は「同じ条件で最後まで成功したか」で判断する

設定を直したら、次の順で元の処理へ戻します。

1. **同じプロセス・接続先で、小さい要求の応答を取得する。** 同じCA、プロキシ、プロジェクト、利用モデルを使い、意図した結果と取得できたリクエストIDを確認します。curlだけの成功で終了しません。
2. **元の方式で1件を最後まで処理する。** ストリーミングなら完了まで受信し、通常の要求なら本文の解析とアプリへの返却まで確認します。長い入力やファイルを使う処理なら、その条件で別に確認します。
3. **並列数を徐々に戻す。** 小さい要求は通るのに負荷を戻すと切れるなら、接続プール、プロキシやNATの容量、クライアントの使い回し、プロセス終了時のクローズ処理を調べます。429へ変わった場合は送信量の問題へ切り分けを進めます。

同じ条件で繰り返し失敗する場合は、原因に合う窓口へ進みます。会社のCA・プロキシで止まるなら社内ネットワーク担当、ゲートウェイで止まるなら提供元、OpenAIからの応答や受領状況を確認したいならOpenAIサポートです。新しいネットワークへ無条件に切り替える前に、失敗が残る場所を伝えます。

問い合わせには、時刻とタイムゾーン、接続先ホストとAPIのパス、SDK・HTTPライブラリのバージョン、実行環境とリージョン、例外と原因の型、経過時間、HTTPステータス、リクエストIDをまとめます。取得できた本文やヘッダーは秘密値を除いた必要部分だけにします。診断ログ全体をそのまま共有せず、プロンプト、認証情報、プロキシの資格情報がないかも確認してください。

## よくある質問

### request IDがないなら、OpenAIには届いていませんか？

断定できません。送信前に失敗した場合だけでなく、サーバーが受け取った後に応答が失われた場合もあります。OpenAIは、対応するエンドポイントで明示的に送った `X-Client-Request-Id` を使い、タイムアウトなどで応答IDを取得できない要求の受領状況をサポートが調べられると説明しています。値はASCIIで512文字以内にし、要求を追跡できる一意の値を使います。[公式のリクエストID説明](https://developers.openai.com/api/reference/overview#supplying-your-own-request-id-with-x-client-request-id)を参照してください。

このIDは、自動的な重複排除や課金取消しを保証するキーではありません。`APIConnectionError` やタイムアウトだけを根拠に未課金と判断せず、受領状況、利用記録、実際の処理結果を照合します。ゲートウェイやAzureでは提供元の追跡方法を確認してください。

### APIキーを作り直すと接続エラーは直りますか？

DNS、証明書検証、プロキシや通信許可の失敗なら、キーの作り直しでは直りません。まず同じプロセスの元の例外を確認します。正しいAPIの接続先から401が返ったときは、キーの有効性や権限、組織・プロジェクトを確認する分岐です。

### curlは通るのにPythonやNodeだけ失敗するのはなぜですか？

使うCA、プロキシ、HTTPライブラリ、実行ユーザーが違う場合があります。Pythonではインストール済み版がHTTPX2か旧HTTPXか、NodeではSDKが使う `fetch` とプロキシ設定が対応しているかを確認します。curlのHTTP応答は経路の一部を確かめる材料で、SDKの生成成功を保証しません。

## 参考資料

本文で参照している外部ページを、登場順に並べています。最終更新日：2026-10-07。

- [OpenAIの公式エラーガイド](https://developers.openai.com/api/docs/guides/error-codes) (developers.openai.com)
- [Pythonリファレンス](https://developers.openai.com/api/reference/python) (developers.openai.com)
- [TypeScriptリファレンス](https://developers.openai.com/api/reference/typescript) (developers.openai.com)
- [curlの公式マニュアル](https://curl.se/docs/manpage.html) (curl.se)
- [Qiita記事「OpenAI API利用時のSSLErrorに対して証明書をダウンロードして解決する」](https://qiita.com/pm00/items/9983bac9f188e73cda20) (qiita.com)
- [OpenAI Status](https://status.openai.com/) (status.openai.com)
- [公式のリクエストID説明](https://developers.openai.com/api/reference/overview) (developers.openai.com)
