OpenAI API「429」「トークン超過」「ChatCompletion」エラー対処法【解決策付き】
OpenAI APIで頻発するエラーの全体像
OpenAI APIを使って開発を進めていると、予期しないエラーに遭遇することは多いです。特に本番環境に移行する段階で、429エラー(レート制限)、トークン超過エラー、ChatCompletionエラーといった主要なエラーが立ちはだかります。これらは発生原因や対処方法が異なるため、正しく理解して対応することが重要です。
なお、LLM APIのエラーは単なる「バグ」ではなく、APIプロバイダーの安定性を守るための正常な制御メカニズムです。エラーを大きく分類すると以下の3種類になります。
- レート制限エラー(429エラー):一定期間内のAPI呼び出し回数が制限を超えた(時間が経つと回復)
- タイムアウトエラー:ネットワーク遅延やAPIサーバーの応答遅延(リトライで解決することが多い)
- リソース不足エラー(503):APIサーバー側の一時的な過負荷(数秒〜数分で回復するケースがほとんど)
エラー1:429「You exceeded your current quota」
症状と発生条件
APIリクエストを送信した際に、以下のエラーメッセージが返される場合があります。
エラーメッセージ(原文):
RateLimitError: 429 You exceeded your current quota, please check your plan and billing details
日本語訳: 「現在のクォータを超過しました。ご自身のプランと請求詳細を確認してください」
このエラーが出るのは、大きく分けて複数の原因があります。月間の利用上限に達した場合、無料トライアル期間の終了、クレジットカードの有効期限切れや無効、APIキーの不正などが代表的です。
なお、同じ429エラーでも「レート制限超過」と「クォータ超過」の2種類があり、対処方法が全く異なります。エラーレスポンスに quota_exceeded や billing details の文言が含まれている場合はクォータ超過、そうでない場合はレート制限超過です。原因を正確に特定するには、以下のようにエラーの詳細を確認してください。
from openai import OpenAI, RateLimitError
import json
client = OpenAI(api_key="your-api-key")
try:
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "こんにちは"}]
)
except RateLimitError as e:
print(f"ステータスコード: {e.status_code}")
print(f"エラーメッセージ: {e.message}")
print(f"レスポンス本文: {json.dumps(e.response.json(), ensure_ascii=False, indent=2)}")
想定される原因
原因1:クレジットカード期限切れ・未払い
OpenAI APIの有料プランを使う場合、クレジットカードの登録が必須です。カードの有効期限切れ、引き落とし失敗、または月単位の利用上限に達したままになっていると、APIへのアクセスがブロックされ429エラーが出ます。この状態では、たとえ新しいカードを登録しても反映に数分〜数時間かかることもあります。
原因2:月単位の利用枠超過(Usage Limits)
OpenAI APIダッシュボードで設定できる「Usage limits」(使用上限)に到達した場合です。上限には以下の2種類があります。
- ハード上限(Hard limit): 月間の最大支出額。この額に達するとAPI呼び出しは即座に止まります
- ソフト上限(Soft limit): 警告メールが届く額。ただし呼び出しは続行できます
月初めにUTC基準でリセットされるまで、この原因でのエラーは解除されません。
原因3:短時間の大量リクエスト(レート制限)
個人のAPIキーの場合、1分間に送信できるトークン数(文字数に相当)に制限があります。OpenAI APIは以下の2種類の制限を同時に持っています。
- トークンベースの制限(TPM): 1分間あたりのトークン数。無料枠は90,000 TPM
- リクエスト数ベースの制限(RPM): 1分間あたりのリクエスト数。無料枠は3 RPM
どちらかに達すると429エラーが返されます。大量のバッチ処理やエージェント実装で同時に複数のリクエストを送ると制限に引っかかりやすく、数秒〜数分待つことで解除されることが多いです。
切り分け手順
- OpenAIの公式ダッシュボード(https://platform.openai.com/account/usage/overview)にログインする
- 左メニューから「Billing」→「Usage」を確認
- 現在の月間利用料金が「Billing」→「Usage limits」で設定したハード上限に達していないか確認
- 「Billing」→「Billing overview」で支払い情報(クレジットカードの有効期限など)を確認
- APIキーが正しく設定されているか、「Settings」→「API keys」で対象のキーが有効か確認
- 同じAPIキーで複数の環境やアプリケーションから並行してリクエストを送っていないか確認
対処方法(優先度順)
対処1:課金情報の更新・プランの確認(最優先)
ダッシュボードの「Billing」→「Billing overview」でクレジットカード情報や有効期限を確認・更新します。無料トライアルからの移行時は「Set up paid account」から明示的に有料プランを有効化する必要があります。また「Billing」→「Usage limits」セクションでハード上限を確認し、必要に応じて引き上げることで継続的にAPIを利用できます。テスト段階では$5〜$10の低めに設定し、本番運用では$50以上に引き上げるのが一般的です。上限変更は即座に反映されます。
なお、上限を引き上げた直後はシステムが変更を反映するのに数分かかることがあります。10分程度待ってから再度リクエストを送ってください。
対処2:リトライロジックを実装する
短時間に大量のリクエストを送っている場合、レート制限に引っかかる可能性があります。リトライロジック(一定時間待機後に再試行)を実装することで、一時的なレート制限を回避できます。特に「指数バックオフ」と呼ばれる、待機時間を段階的に長くする戦略が有効です。1回目は2秒、2回目は4秒、3回目は8秒…というように倍々で増やすことで、サーバーが回復するまでの余裕を確保しつつ、大量のリトライによるさらなる圧迫を防げます。
また、複数のプログラムが同時に同じAPIにアクセスする場合、全員が同じ間隔でリトライするとまたすぐ制限に達してしまいます。これを防ぐため「ジッター」(ランダムな遅延)を加えることも重要です。
Python例:
import time
import random
from openai import OpenAI
client = OpenAI(api_key="your-api-key")
def call_with_retry(prompt, max_retries=5, initial_delay=2):
for attempt in range(max_retries):
try:
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
return response
except Exception as e:
if "429" in str(e):
if attempt == max_retries - 1:
raise
# 指数バックオフ+ジッター
wait_time = initial_delay * (2 ** attempt)
jitter = wait_time * (0.8 + random.random() * 0.4)
print(f"Rate limited. Waiting {jitter:.1f} seconds...")
time.sleep(jitter)
else:
raise
また、単純なリトライループでサーバーをさらに圧迫しないよう注意が必要です。while Trueで待機なしに無限リトライするのは避けてください。必ず最大リトライ回数を設定しましょう。
なお、HTTPレスポンスにはRetry-Afterヘッダーが含まれることがあります。このヘッダーが指定する秒数を優先的に待機時間として使用することで、より的確なリトライが実現できます。
対処3:バッチ処理で利用料を最適化
多数のリクエストを同時に送らず、時間を分散させることでレート制限を回避します。また、OpenAIのBatch API(バッチ処理API)を使うと、低い優先度で大量処理が可能になり、月間利用料も通常より安くなる傾向があります。ただしバッチAPIは処理に数時間〜24時間かかるため、リアルタイム処理には向きません。夜間のデータ処理やレポート生成など、時間的な余裕がある用途に適しています。詳細はOpenAI公式ドキュメント(https://platform.openai.com/docs/guides/batch)で確認できます。
対処4:複数のAPIキーでリクエストを分散
エージェントシステムで大量のリクエストを処理する場合、複数のAPIキーでリクエストを分散する方法も効果的です。1つのキーが上限に達しても他のキーで続行できます。なお、OpenAIの利用規約ではレート制限回避を明示的な目的とした複数キーの使用は推奨されていない点に注意してください。
import os
from openai import OpenAI
api_keys = [
os.getenv("OPENAI_API_KEY_1"),
os.getenv("OPENAI_API_KEY_2"),
os.getenv("OPENAI_API_KEY_3"),
]
current_key_index = 0
def call_with_key_rotation(messages):
global current_key_index
api_key = api_keys[current_key_index % len(api_keys)]
current_key_index += 1
client = OpenAI(api_key=api_key)
return client.chat.completions.create(
model="gpt-4o",
messages=messages
)
エラー2:トークン超過「This model’s maximum context length is 4097 tokens」
症状と発生条件
プロンプトと入力テキストを合わせたトークン数(文字数換算)が、モデルの上限を超えた場合に発生します。
エラーメッセージ(原文):
"This model's maximum context length is 4097 tokens, however you requested 5000 tokens"
日本語訳: 「このモデルの最大コンテキスト長は4097トークンですが、5000トークンがリクエストされました」
このエラーはgpt-3.5-turboなど比較的古いモデルを使っている場合に頻発します。gpt-4-turboやgpt-4oといった新しいモデルはもっと大きなコンテキスト長を持つため、同じ量のテキストでは超過しにくくなります。
想定される原因
モデルごとに処理できるテキスト量の上限が決まっています。gpt-3.5-turboは約4096トークンが上限で、「入力プロンプト+max_tokens(生成文字数)」の合計がこれを超えると発生します。プロンプト、ユーザーの質問、会話履歴を全部合わせると容易にこの上限を超えるため、特に長めのドキュメント処理や会話が長くなったユースケースで問題になります。
切り分け手順
- 使用しているモデルの正確な名前を確認(gpt-3.5-turboなのかgpt-4なのか)
- OpenAIの公式ドキュメントでそのモデルの「max_tokens」を確認
- 送信しているプロンプト全体(システムメッセージ+ユーザーメッセージ+会話履歴)の文字数をざっくり数える
max_tokensパラメータの値を確認し、合計値がモデルの上限を超えていないか計算- オンラインのトークンカウンターツール(例:https://platform.openai.com/tokenizer)で正確なトークン数を測定
対処方法(優先度順)
対処1:新しいモデル(gpt-4oやgpt-4-turbo)に変更する
新しいモデルほどコンテキスト長が大きいため、同じテキスト量でもトークン超過しにくくなります。料金は若干上がりますが、実装の複雑さを減らせます。
response = client.chat.completions.create(
model="gpt-4o", # 古いgpt-3.5-turboからアップグレード
messages=[{"role": "user", "content": prompt}]
)
対処2:max_tokensを調整し、会話履歴を古い順に削除する
max_tokensパラメータを小さくして生成テキストを制限します。またチャットアプリケーションで会話が長くなった場合、古いメッセージから順に削除することでトークン数を削減します。直近10会話だけを送信する、など制限をかけることが一般的です。
対処3:長いテキストは要約・分割してから送信する
ドキュメント処理の場合、元のテキストをそのまま送るのではなく、別のAPI呼び出しで先に要約してから、その要約を使うという2段階の処理パターンが有効です。長いテキストを複数のチャンクに分割して処理することも有効です。
エラー3:「This is a chat model and not supported in the v1/completions endpoint」
症状と発生条件
gpt-3.5-turboやgpt-4などのチャットモデルに対して、Completionsエンドポイント(v1/completions)でリクエストすると以下が返されます。
エラーメッセージ(原文):
"Invalid request error: This model is a chat model and not supported in the v1/completions endpoint. Did you mean to use /v1/chat/completions?"
日本語訳: 「このモデルはチャットモデルであり、v1/completionsエンドポイントではサポートされていません。/v1/chat/completionsを使用する意図でしたか?」
想定される原因
gpt-3.5-turboやgpt-4といったチャットモデルは、従来のCompletions APIではなく、Chat Completions APIの専用エンドポイント(/v1/chat/completions)に対応しています。古いCompletionsエンドポイントを利用しているコードをそのまま新しいモデルに流用すると発生します。
切り分け手順
- 使用しているモデル名を確認
- OpenAI公式ドキュメントでそのモデルがChat Completionsに対応しているか確認
- コード内でどのエンドポイントを呼び出しているか確認
対処方法(優先度順)
対処1:Chat Completions APIを使用する(推奨)
from openai import OpenAI
client = OpenAI(api_key="your-api-key")
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "あなたは有用なアシスタントです"},
{"role": "user", "content": "こんにちは"}
]
)
print(response.choices[0].message.content)
対処2:従来のCompletionsモデルを使用する
チャットボット以外の用途(文章生成、翻訳など)では、従来のCompletions APIに対応したモデルを選択することも選択肢の一つです。ただしtext-davinci-003などの旧来モデルは非推奨となっていることが多いため、基本的には対処1が推奨です。
エラー4:ChatCompletionエラー「‘ChatCompletion’ object is not subscriptable」
症状と発生条件
APIレスポンスを取得した後、レスポンスをリスト形式でアクセスしようとすると発生するエラーです。
エラーメッセージ(原文):
"TypeError: 'ChatCompletion' object is not subscriptable"
日本語訳: 「ChatCompletionオブジェクトは添字でアクセスできません」
このエラーは主に、OpenAIのPythonライブラリのバージョン更新に伴う使い方の変更が原因になります。古いバージョン(1.0以前)ではレスポンスが辞書形式だったのに対し、新しいバージョン(v0.27.0以降)ではオブジェクト形式になりました。
想定される原因
OpenAI Pythonライブラリのアップデートにより、APIレスポンスの形式が変更されました。古いコード(response['choices'][0]といったリスト形式でアクセス)が新しいライブラリで動作しなくなります。混在環境や参考資料が古い場合に頻発します。
切り分け手順
- インストールされているOpenAIライブラリのバージョンを確認
pip show openai - バージョンがv0.27.0以降なら新しい形式での記述が必要
- コード内でレスポンスにアクセスしている部分を確認
- 古い形式の記述(
response['choices'][0]['message']['content'])と新しい形式(response.choices[0].message.content)を識別
対処方法(優先度順)
対処1:ライブラリを最新版にアップグレードしてコードを修正
まずはライブラリを最新にアップグレードし、コードの記述方法を新形式に統一します。
pip install --upgrade openai
古いコード:
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "こんにちは"}]
)
answer = response['choices'][0]['message']['content']
新しいコード:
from openai import OpenAI
client = OpenAI(api_key="your-api-key")
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "こんにちは"}]
)
answer = response.choices[0].message.content
対処2:古いバージョンを継続利用する場合
どうしても古い環境を使う必要がある場合、古いライブラリを明示的にインストールします。ただしセキュリティ対応が受けられなくなるため、推奨できません。
pip install openai==0.26.5
対処3:複数のバージョン対応コードを書く
両方のバージョンに対応したコードを書くことで、移行期間を設けることができます。
try:
# 新形式
answer = response.choices[0].message.content
except AttributeError:
# 古い形式
answer = response['choices'][0]['message']['content']
エラー5:429 Too Many Requests(レート制限)
症状と発生条件
短時間に多数のリクエストを送信すると以下が返されます。
エラーメッセージ(原文):
RateLimitError: 429 Too Many Requests
日本語訳: 「リクエストが多すぎます」
429エラー(クォータ超過)と似ていますが、こちらは課金上限ではなく純粋なリクエスト頻度の問題です。エラーメッセージには制限の詳細が含まれており、以下のような情報が確認できます。
{
"error": {
"message": "Rate limit reached for gpt-4 in organization org-XXXX on tokens per min. Limit: 90000, Used: 90000, Requested: 5000. Please try again in 1s.",
"type": "rate_limit_error",
"param": null,
"code": "rate_limit_exceeded"
}
}
このメッセージから以下のことが分かります:
- モデル: gpt-4
- 制限タイプ: トークン数(tokens per min)
- 制限値: 1分あたり90,000トークン
- 既に使用済み: 90,000トークン
- 今回要求した量: 5,000トークン
- 再試行推奨時間: 1秒
なお、HTTPレスポンスにはRetry-Afterヘッダーが含まれることがあります。このヘッダーが指定する秒数を優先的に待機時間として使用することで、より的確なリトライが実現できます。
想定される原因
OpenAI APIは、アカウントの種類とプランに応じてリクエスト数に制限を設けています。主な原因は以下の通りです。
- 同時実行数が制限を超えている:並列処理(マルチスレッド、asyncio)で処理数を制限しないと瞬時に大量のリクエストが送られます
- リトライロジックがない:失敗したリクエストを即座に再送すると、制限にすぐ引っかかります
- プランのレート制限が厳しすぎる:無料プランは特に制限が厳しく(例:毎分3リクエスト)、ループ処理やバッチ処理で制限を超えた場合に発生します
- APIキーの共有・複数プロジェクトでの流用:同じキーを使い回すと、他の処理のリクエストもカウントされ、気づかないうちに制限に達します
なお、rate_limit_exceededとquota_exceededは同じ429エラーでも性質が異なります。前者はリトライで回復できる可能性がありますが、後者はクレジット追加が必要なため、エラーメッセージを必ず確認して対応を分けてください。
切り分け手順
- ダッシュボード → Billingで現在のプラン(Free / Pay As You Go)を確認
- 実装コードで同時実行やループ処理がないか確認
- 短時間に集中しているリクエストを分散できないか検討
対処方法(優先度順)
対処1:リクエスト間に待機を挿入する
import time
from openai import OpenAI
client = OpenAI(api_key="your-api-key")
messages_list = [
[{"role": "user", "content": "質問1"}],
[{"role": "user", "content": "質問2"}],
[{"role": "user", "content": "質問3"}]
]
for messages in messages_list:
response = client.chat.completions.create(
model="gpt-4o",
messages=messages
)
print(response.choices[0].message.content)
time.sleep(1) # 各リクエスト間に1秒待機
無料プラン(1分間に3リクエスト)の場合、最低20秒間隔でリクエストを送れば安全です。有料プランでも同様の方法で調整できます。
対処2:指数バックオフでリトライする
失敗時に待機時間を段階的に増やしながら再試行します。Retry-Afterヘッダーがある場合はその値を優先して使用します。
import time
from openai import OpenAI, RateLimitError
client = OpenAI(api_key="your-api-key")
def call_openai_with_backoff(messages, max_retries=5):
for attempt in range(max_retries):
try:
response = client.chat.completions.create(
model="gpt-4o",
messages=messages
)
return response
except RateLimitError as e:
if attempt == max_retries - 1:
raise
# Retry-Afterヘッダを優先、なければ指数バックオフ
retry_after = e.response.headers.get("Retry-After")
wait_time = int(retry_after) if retry_after else 2 ** attempt
print(f"Rate limit. Waiting {wait_time}s before retry...")
time.sleep(wait_time)
except Exception as e:
raise
response = call_openai_with_backoff([{"role": "user", "content": "テスト"}])
対処3:同時実行数を制限する
並列処理を使う場合、Semaphoreやスレッドプールで同時実行数を制御します。
import asyncio
from openai import AsyncOpenAI
from asyncio import Semaphore
client = AsyncOpenAI(api_key="your-api-key")
# 同時実行数を3に制限
semaphore = Semaphore(3)
async def call_openai_async(prompt):
async with semaphore:
response = await client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
return response
prompts = ["質問1", "質問2", "質問3", "質問4", "質問5"]
tasks = [call_openai_async(p) for p in prompts]
results = await asyncio.gather(*tasks)
対処4:リクエストキューイングで事前対策する
大量のリクエストを処理する場合、キューイングシステムを導入することでレート制限内に収まるようにリクエストを調整できます。
import queue
import threading
import time
from typing import Callable, Any
class RateLimitedQueue:
"""
レート制限に対応したリクエストキュー
"""
def __init__(self, requests_per_minute: int = 30):
self.queue = queue.Queue()
self.requests_per_minute = requests_per_minute
self.interval = 60.0 / requests_per_minute
self.last_request_time = 0
self.lock = threading.Lock()
def add_request(self, func: Callable, *args, **kwargs) -> Any:
self.queue.put((func, args, kwargs))
def start_worker(self):
worker_thread = threading.Thread(target=self._process_queue, daemon=True)
worker_thread.start()
def _process
---
## あわせて読みたい
- [Claude Code「Connection timeout」エラーの原因と解決方法|3つの対処法](/code/claude-code-connection-timeout/)
- [Claude Codeのトークン消費を98%削減する方法【MCP活用+コンテキスト最適化】](/code/claude-code-token-consumption-reduction/)
- [AIから正確な回答をもらう7つのプロンプト術【Claude・ChatGPT】](/code/ai-7-2/)
参考ソース
- OpenAI API error 429: You exceeded your current quota, please check your plan and billing details
- OpenAI Python Package Error: 'ChatCompletion' object is not subscriptable
- OpenAI GPT-3 API error: This model's maximum context length is 4097 tokens
- OpenAI API error: This is a chat model and not supported in the v1/completions endpoint
- OpenAI API giving error: 429 Too Many Requests
- Stop Bleeding Money on OpenAI: A Practical Guide to Slashing Your API Bills