Claude API を初めて使用する際、さまざまなエラーが発生することがあります。認証エラー、レート制限、リクエスト形式エラーなど、最初の API 呼び出しでぶつかりやすい9つの問題と、その解決方法をご説明します。
Q1: 401 認証エラー(Unauthorized)または API キーが認識されない
原因
API キーが設定されていない、無効であるか、または形式が間違っています。
解決法
ステップ1:API キーを確認
- Anthropic コンソール にログイン
- 「API Keys」セクションで新しいキーを生成
- キーをコピー(
sk-ant-で始まります)
ステップ2:API キーを設定
Python の場合:
import anthropic
# 方法1:環境変数(推奨)
# 実行前に:export ANTHROPIC_API_KEY="sk-ant-..."
client = anthropic.Anthropic() # 自動的に ANTHROPIC_API_KEY を読み込む
# 方法2:直接指定(テスト時のみ)
client = anthropic.Anthropic(api_key="sk-ant-your-key-here")
# 方法3:確認
print(client.api_key) # 最初の数文字のみ表示されるNode.js/JavaScript の場合:
import Anthropic from "@anthropic-ai/sdk";
// 方法1:環境変数(推奨)
// 実行前に:export ANTHROPIC_API_KEY="sk-ant-..."
const client = new Anthropic(); // 自動的に環境変数を読み込む
// 方法2:直接指定
const client = new Anthropic({
apiKey: "sk-ant-your-key-here",
});cURL の場合:
# ヘッダーに API キーを指定
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: sk-ant-your-key-here" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{...}'ステップ3:環境変数を確認
# API キーが設定されているか確認
echo $ANTHROPIC_API_KEY
# 最初の10文字が表示されるか確認
echo $ANTHROPIC_API_KEY | head -c 10ステップ4:キーの有効性をテスト
# cURL でテスト
curl -s https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-opus-4-1","messages":[{"role":"user","content":"test"}],"max_tokens":100}' \
| head -c 200
# 200 OK が返ればキーは有効:::warning API キー漏洩時の対応:
- コンソールで問題のキーを削除
- 新しいキーを生成
- コード内で新しいキーに置き換え
- git commit 履歴を確認(キーが含まれていないか)
漏洩したキーで実行された API 呼び出しについては、Anthropic サポートに連絡してください。 :::
Q2: 429 エラー(Too Many Requests)- レート制限に達した
原因
API の使用制限(分単位、日単位のレート制限)に達しました。または大量のリクエストを短時間で送信しています。
解決法
ステップ1:レート制限の内容を確認
# レスポンスヘッダーを確認
curl -i https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{...}'
# レスポンスに以下が含まれます:
# x-ratelimit-limit-requests: 6000
# x-ratelimit-limit-tokens: 2000000
# x-ratelimit-remaining-requests: 5999
# x-ratelimit-reset-requests: 2026-03-21T18:05:00Zステップ2:リトライロジックを実装
Python の例:
import anthropic
import time
from typing import Optional
def call_claude_with_retry(
client: anthropic.Anthropic,
max_retries: int = 5,
backoff_factor: float = 2.0
) -> Optional[str]:
"""リトライロジック付きの API 呼び出し"""
for attempt in range(max_retries):
try:
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=1024,
messages=[
{"role": "user", "content": "Hello, Claude!"}
]
)
return response.content[0].text
except anthropic.RateLimitError as e:
if attempt == max_retries - 1:
raise # 最後の試行で失敗した場合は例外を投げる
# 指数バックオフで待機
wait_time = backoff_factor ** attempt
print(f"Rate limited. Waiting {wait_time} seconds...")
time.sleep(wait_time)
except anthropic.APIError as e:
print(f"API Error: {e}")
raise
# 使用例
client = anthropic.Anthropic()
result = call_claude_with_retry(client)
print(result)Node.js の例:
import Anthropic from "@anthropic-ai/sdk";
async function callClaudeWithRetry(
client,
maxRetries = 5,
backoffFactor = 2.0
) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await client.messages.create({
model: "claude-opus-4-1",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello, Claude!" }],
});
return response.content[0].text;
} catch (error) {
if (error.status === 429) {
if (attempt === maxRetries - 1) throw error;
const waitTime = Math.pow(backoffFactor, attempt) * 1000;
console.log(`Rate limited. Waiting ${waitTime}ms...`);
await new Promise((resolve) => setTimeout(resolve, waitTime));
} else {
throw error;
}
}
}
}
const client = new Anthropic();
const result = await callClaudeWithRetry(client);
console.log(result);ステップ3:リクエストの並行処理を制限
# ❌ 悪い例(並行リクエストが多すぎる)
import asyncio
async def bad_example():
tasks = [
client.messages.create(
model="claude-opus-4-1",
max_tokens=100,
messages=[{"role": "user", "content": f"Task {i}"}]
)
for i in range(100) # 100 個を同時実行
]
return await asyncio.gather(*tasks)
# ✅ 良い例(並行数を制限)
import asyncio
from asyncio import Semaphore
async def good_example():
semaphore = Semaphore(5) # 最大 5 個の並行リクエスト
async def limited_request(i):
async with semaphore:
return await client.messages.create(
model="claude-opus-4-1",
max_tokens=100,
messages=[{"role": "user", "content": f"Task {i}"}]
)
tasks = [limited_request(i) for i in range(100)]
return await asyncio.gather(*tasks):::tip フリーティアと有料アカウントで異なるレート制限があります:
- フリーティア:1分あたり6,000リクエスト、1日あたり約2百万トークン
- 有料:プラン次第で異なります
無料枠を超える場合は、支払いプランにアップグレードしてください。 :::
Q3: 400 エラー(Bad Request)- リクエスト形式が不正
原因
モデル名のタイプミス、必須フィールドが不足、または無効なパラメータが含まれています。
解決法
ステップ1:モデル名を確認
# ❌ 間違ったモデル名
response = client.messages.create(
model="claude-opus", # ❌ バージョンなし
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
# ✅ 正しいモデル名
response = client.messages.create(
model="claude-opus-4-1", # または claude-sonnet-4-20250514
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)利用可能なモデル一覧:
- claude-opus-4-1(フル機能、最高性能)
- claude-sonnet-4-20250514(バランス型)
- claude-haiku-4-5-20251001(高速、軽量)
ステップ2:必須フィールドを確認
# ✅ 必須フィールド
response = client.messages.create(
model="claude-opus-4-1", # 必須
max_tokens=1024, # 必須
messages=[ # 必須
{"role": "user", "content": "Hello"}
]
)
# ❌ 必須フィールド不足の例
response = client.messages.create(
model="claude-opus-4-1"
# max_tokens を指定していない → エラー
)ステップ3:パラメータ値を確認
# ❌ 無効なパラメータ値
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=0, # ❌ 0 は無効(最小値は1)
temperature=-0.5, # ❌ 負の値は無効(0.0~1.0)
top_p=1.5, # ❌ 1.0を超える値は無効
messages=[{"role": "user", "content": "Hello"}]
)
# ✅ 有効なパラメータ値
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=1024, # 1~200000
temperature=0.7, # 0.0~1.0
top_p=0.9, # 0.0~1.0
messages=[{"role": "user", "content": "Hello"}]
)ステップ4:メッセージ形式を確認
# ❌ 間違ったメッセージ形式
messages = [
"Hello, Claude!" # ❌ 文字列だけではダメ
]
# ✅ 正しいメッセージ形式
messages = [
{
"role": "user", # "user" または "assistant"
"content": "Hello, Claude!" # 文字列またはコンテンツブロック
}
]
# ✅ 複雑なコンテンツの例
messages = [
{
"role": "user",
"content": [
{
"type": "text",
"text": "What's in this image?"
},
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": "base64-encoded-image-data"
}
}
]
}
]ステップ5:エラーメッセージの詳細を確認
try:
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
except anthropic.BadRequestError as e:
print(f"Error type: {e.error}")
print(f"Error message: {e.message}")
print(f"Request: {e.request}")
# エラーメッセージに詳細情報が含まれます:::warning API リファレンスで各パラメータの許可値を確認してください。特に max_tokens の範囲とモデルごとの制限に注意。 :::
Q4: レスポンスが空、または max_tokens が小さすぎる
原因
max_tokens の値が小さすぎてレスポンスが切り詰められた、または応答にデータが含まれていません。
解決法
ステップ1:max_tokens を確認
# ❌ max_tokens が小さすぎる例
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=1, # ❌ 文字数がほぼ0
messages=[{"role": "user", "content": "Write a 500 word essay"}]
)
# 結果:ほぼ空のレスポンス
# ✅ 適切な max_tokens
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=2048, # 一般的な値
messages=[{"role": "user", "content": "Write an essay"}]
)ステップ2:レスポンスが完全であるか確認
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
# レスポンスの完全性を確認
if response.stop_reason == "end_turn":
print("✓ レスポンス完全")
elif response.stop_reason == "max_tokens":
print("❌ max_tokens に達して切り詰められた")
# max_tokens を増やす必要があります
else:
print(f"Stop reason: {response.stop_reason}")ステップ3:レスポンス内容を確認
# レスポンスが空でないか確認
if response.content:
text = response.content[0].text
print(f"Length: {len(text)} characters")
else:
print("レスポンスが空です")
# 完全なレスポンス構造を確認
print(f"Stop reason: {response.stop_reason}")
print(f"Usage: {response.usage}")
print(f"Content blocks: {len(response.content)}")ステップ4:プロンプトを確認
# ❌ 曖昧なプロンプト
messages = [{"role": "user", "content": ""}]
# ✅ 明確なプロンプト
messages = [{"role": "user", "content": "以下の Python コードについて説明してください:[code]"}]:::tip モデルごとのコンテキストウィンドウ制限:
- Claude Opus 4.1:200,000トークン
- Claude Sonnet 4:200,000トークン
- Claude Haiku:200,000トークン
max_tokens はコンテキストウィンドウ内に収まるよう設定してください。 :::
Q5: ストリーミングが動作しない、または部分的なレスポンスしか返らない
原因
ストリーミングの実装が不正、ネットワーク接続が切断、またはリクエストが不完全です。
解決法
ステップ1:ストリーミングの基本的な実装
Python の例:
import anthropic
client = anthropic.Anthropic()
# ✅ ストリーミングを有効にしたリクエスト
with client.messages.stream(
model="claude-opus-4-1",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude!"}]
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print() # 改行Node.js の例:
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const stream = await client.messages.stream({
model: "claude-opus-4-1",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello, Claude!" }],
});
for await (const chunk of stream) {
if (
chunk.type === "content_block_delta" &&
chunk.delta.type === "text_delta"
) {
process.stdout.write(chunk.delta.text);
}
}ステップ2:ストリーミングのエラー処理
# エラーハンドリング付きストリーミング
try:
with client.messages.stream(
model="claude-opus-4-1",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
) as stream:
full_response = ""
for text in stream.text_stream:
full_response += text
print(text, end="", flush=True)
# ストリーム完了後に最終データを確認
final_message = stream.get_final_message()
print(f"\nStop reason: {final_message.stop_reason}")
except anthropic.APIError as e:
print(f"Stream error: {e}")ステップ3:タイムアウト設定
# タイムアウト付きストリーミング
client = anthropic.Anthropic(timeout=60.0) # 60秒
try:
with client.messages.stream(
model="claude-opus-4-1",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
except anthropic.APITimeoutError:
print("Request timed out after 60 seconds")ステップ4:ネットワーク接続を確認
# API エンドポイント への接続テスト
curl -I https://api.anthropic.com
# 200 OK が返ればネットワークは正常:::warning ストリーミング中は以下に注意:
- バッファサイズが大きすぎるとメモリを消費
- 長時間のストリーミングはタイムアウトの可能性
- flush() でバッファをクリアしてリアルタイム表示 :::
Q6: Tool use のレスポンス形式が不正、または期待と異なる
原因
tool_use パラメータの形式が不正、tool_choice の設定が不適切、またはツール定義が不完全です。
解決法
ステップ1:ツール定義を確認
# ✅ 正しいツール定義
tools = [
{
"name": "calculator",
"description": "数値を計算するツール",
"input_schema": {
"type": "object",
"properties": {
"operation": {
"type": "string",
"enum": ["add", "subtract", "multiply", "divide"],
"description": "実行する操作"
},
"x": {
"type": "number",
"description": "最初の数値"
},
"y": {
"type": "number",
"description": "2番目の数値"
}
},
"required": ["operation", "x", "y"]
}
}
]ステップ2:tool_use を含むリクエスト
# ✅ ツール使用を含むリクエスト
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=1024,
tools=tools,
messages=[
{"role": "user", "content": "5 + 3 は何ですか?"}
]
)
# レスポンスにツール呼び出しが含まれるか確認
for block in response.content:
if block.type == "tool_use":
print(f"Tool: {block.name}")
print(f"Input: {block.input}")ステップ3:tool_choice を設定
# ツール使用の挙動を制御
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=1024,
tools=tools,
tool_choice={
"type": "auto" # ツール使用を自動判定
},
messages=[{"role": "user", "content": "計算してください"}]
)
# または特定のツールを強制使用
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=1024,
tools=tools,
tool_choice={
"type": "tool",
"name": "calculator" # このツールを使用するよう強制
},
messages=[{"role": "user", "content": "計算してください"}]
)ステップ4:ツール結果をループバック
messages = [
{"role": "user", "content": "15 + 20 を計算してください"}
]
while True:
# API 呼び出し
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=1024,
tools=tools,
messages=messages
)
# アシスタント応答をメッセージに追加
messages.append({"role": "assistant", "content": response.content})
# ツール呼び出しがあるか確認
tool_calls = [block for block in response.content if block.type == "tool_use"]
if not tool_calls:
# ツール呼び出しがない場合は終了
break
# ツール実行結果をメッセージに追加
for tool_call in tool_calls:
# ツールを実行(ここでは簡略化)
if tool_call.name == "calculator":
result = eval(f"{tool_call.input['x']} {tool_call.input['operation']} {tool_call.input['y']}")
messages.append({
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_call.id,
"content": str(result)
}
]
})
# 最終応答を取得
final_response = messages[-1]:::warning ツール定義では以下に注意:
- input_schema は JSON Schema に準拠する必要がある
- required フィールドに必須プロパティをすべて指定
- description フィールドは詳細に(Claude がツール選択時に参考にする) :::
Q7: Context window を超過したエラー
原因
入力テキストが長すぎて、モデルの最大コンテキストウィンドウを超えています。
解決法
ステップ1:エラーを確認
try:
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=1024,
messages=[
{"role": "user", "content": very_long_text}
]
)
except anthropic.BadRequestError as e:
if "context_length_exceeded" in str(e):
print("Context window exceeded!")
# 解決策:テキストを分割ステップ2:テキストを分割
# ❌ 大きすぎるテキストを1つのリクエストで処理
long_text = "..." * 100000 # 非常に長い
# ✅ テキストを分割して処理
def process_large_text(text, chunk_size=10000):
chunks = [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]
summaries = []
for i, chunk in enumerate(chunks):
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=1024,
messages=[
{
"role": "user",
"content": f"このセクション {i+1}/{len(chunks)} を要約してください:\n{chunk}"
}
]
)
summaries.append(response.content[0].text)
return summariesステップ3:会話履歴を管理
# ✅ 会話履歴のサイズを制限
def manage_conversation_history(messages, max_messages=10):
"""最新のメッセージのみを保持"""
if len(messages) > max_messages:
# システムメッセージは保持、古いメッセージを削除
system_msg = [m for m in messages if m.get("role") == "system"]
recent_msg = messages[-(max_messages-len(system_msg)):]
return system_msg + recent_msg
return messagesステップ4:コンテキストウィンドウを確認
# API レスポンスから使用トークン数を確認
response = client.messages.create(
model="claude-opus-4-1",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
print(f"Input tokens: {response.usage.input_tokens}")
print(f"Output tokens: {response.usage.output_tokens}")
print(f"Total: {response.usage.input_tokens + response.usage.output_tokens}"):::tip コンテキストウィンドウの目安:
- Claude Opus 4.1:200,000トークン(約150万単語)
- 日本語の場合、約100万字
大規模な文書処理の場合は、複数リクエストに分割することをお勧めします。 :::
Q8: 「tool_result could not be submitted」エラーで会話が止まる
原因
tool_use ブロックと tool_result ブロックの対応が崩れていることが、ほぼすべての原因です。具体的には、tool_use_id が一致していない、アシスタントの tool_use ターンを messages に積まずにいきなり tool_result を送っている、複数の tool_use があるのに一部の tool_result しか返していない、といったケースです。
Claude は「直前のアシスタント応答に含まれる tool_use と、次のユーザーターンの tool_result が1対1で揃っていること」を厳密に要求します。1つでも欠けると、リクエスト全体が拒否されます。
個人開発でツールを何本も束ねていると、結果の取りこぼしは特に起きやすくなります。ループ処理の中で1つだけ append を忘れる、といった形で紛れ込みます。
解決法
ステップ1:アシスタント応答をそのまま messages に積む
response = client.messages.create(
model="claude-opus-4-1", max_tokens=1024, tools=tools, messages=messages
)
# response.content(tool_use ブロックを含む)を丸ごと積むのが要です
messages.append({"role": "assistant", "content": response.content})tool_use ブロックを自分で組み立て直す必要はありません。返ってきた response.content をそのまま渡すのが、最も壊れにくい方法です。
ステップ2:すべての tool_use に tool_result を返す
tool_uses = [b for b in response.content if b.type == "tool_use"]
tool_results = []
for tu in tool_uses:
try:
output = run_tool(tu.name, tu.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": tu.id, # ← ここが一致していないと弾かれます
"content": str(output),
})
except Exception as e:
# 失敗しても tool_result は返す。is_error を立てるのが作法です
tool_results.append({
"type": "tool_result",
"tool_use_id": tu.id,
"content": f"Error: {e}",
"is_error": True,
})
# 複数の結果は1つのユーザーメッセージにまとめて返します
messages.append({"role": "user", "content": tool_results})ツールが3つ呼ばれたら、tool_result も3つ。1つでも欠けたまま送ると、このエラーになります。
:::warning よくある取りこぼし:
- tool_use_id をタイプミス、または別の呼び出しの id を使っている
- ツール実行が例外で落ちて tool_result を append し忘れる(→ is_error を立てて必ず返す)
- tool_result の前にテキストブロックを差し込んでいる(content 配列は tool_result から始める) :::
Q9: 「Spanner temporarily unavailable」が突然返ってくる
原因
これはあなたのコードの問題ではありません。Anthropic 側のバックエンド(分散データベース層)が一時的に応答できない状態を示す、サーバー由来の一過性エラーです。529(Overloaded)や 500 系と同じく、時間をおけば回復します。
私自身、初めてこの表示を見たときは設定を疑って手が止まりましたが、原因はこちら側にありませんでした。リクエスト形式が正しい前提なら、リトライ設計を整えるだけで十分です。
解決法
ステップ1:一過性エラーとして指数バックオフで再試行
import time, random
import anthropic
def create_with_retry(client, max_retries=5, **kwargs):
for attempt in range(max_retries):
try:
return client.messages.create(**kwargs)
except (anthropic.InternalServerError, anthropic.APIStatusError) as e:
msg = str(e).lower()
transient = "spanner" in msg or "overloaded" in msg or "temporarily" in msg
if not transient or attempt == max_retries - 1:
raise
# 指数バックオフ + ジッター(同時再試行の集中を避ける)
wait = min(2 ** attempt, 30) + random.uniform(0, 1)
time.sleep(wait)ステップ2:すぐに叩き直さない 回復前に短い間隔で再試行を連打すると、かえって混雑を長引かせます。1回目は1〜2秒、その後2倍ずつ広げ、上限を設けるのが安全です。
:::tip 判断の目安:
Spanner temporarily unavailable/Overloaded/ 500・529 → サーバー側の一過性。バックオフで再試行- 400・401・404 → こちらのリクエストの問題。リトライしても直りません
継続して頻発する場合は、Anthropic のステータスページで障害情報を確認してください。 :::
全体を振り返って
Claude API の初期設定エラーは、以下の9つのステップで解決できます:
- API キーが正しく設定されているか確認(401エラーの解決)
- リクエストの並行数を制限(429レート制限の解決)
- リクエスト形式を確認(400エラーの解決)
- max_tokens を適切に設定(空レスポンスの解決)
- ストリーミング実装を確認(ストリーミング失敗の解決)
- ツール定義を正確に記述(tool_use エラーの解決)
- テキストを分割して処理(context window の解決)
- tool_use と tool_result を1対1で揃える(tool_result submission エラーの解決)
- サーバー由来の一過性エラーはバックオフで再試行(Spanner temporarily unavailable の解決)
エラーが発生した場合は、エラーメッセージの全文を保存し、エラーコードを確認してください。ほとんどの初期設定エラーは、これらのチェックポイントのいずれかで解決します。
Happy coding with Claude API!