◉CLAUDE LABEN
●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り45日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り45日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました
記事一覧/Claude.ai
◉ Claude.ai/2026-05-04中級

「tool result could not be submitted」エラーが出たときの完全対処ガイド

Claudeで突然現れる「tool result could not be submitted」エラーは、ドキュメントに詳しい記載が少なく原因特定に時間がかかります。このエラーが出る場面の整理、主な原因と対処法、デバッグ手順のまとめ、よくある疑問への回答を個人開発者の実体験をもとに解説します。

tool-use23エラー解決3API27トラブルシューティング51ツール使用

Claudeを使って開発していると、突然「tool result could not be submitted」というエラーに遭遇することがあります。しかも、このエラーはドキュメントに詳しく書かれていないことが多く、原因の特定に時間がかかってしまいます。

私自身も Claude の tool use 機能を実装しているときに何度かこのエラーで詰まりました。試行錯誤の末にパターンを掴めてきたので、今回は原因と対処法をまとめておきます。

このエラーはどんな場面で出るか

「tool result could not be submitted」は、Claude の tool use(ツール使用)機能を利用しているときに発生するエラーです。具体的には次のような流れで起きます。

  1. ユーザーがメッセージを送信する
  2. Claude がツール呼び出しを判断して tool_use ブロックを含む応答を返す
  3. あなたのコードがそのツールを実行して結果を取得する
  4. その結果を tool_result として Claude に送り返す

この4番目のステップが失敗すると、このエラーが出ます。エラーメッセージだけ見ると「Claudeが結果を受け取れなかった」ように読めますが、実際には原因がいくつかあります。

主な原因と対処法

1. ツール結果が大きすぎる(最も多い原因)

これが一番よく見るケースです。たとえばウェブ検索ツールで取得したHTMLをそのまま返したり、データベースから大量のレコードを返したりすると、コンテキストウィンドウを超えてしまいます。

Claude のコンテキスト制限(現在の多くのモデルで20万トークン前後)を超えると、ツール結果が受け付けられなくなります。

対処法: ツール結果を必ず前処理して、本当に必要な情報だけを返すようにしましょう。

# ❌ 生のHTMLをそのまま返す(危険)
def search_web(query: str) -> str:
    response = requests.get(f"https://example.com/search?q={query}")
    return response.text  # 何万文字もある可能性がある
 
# ✅ 必要な情報だけ抽出して返す(正しい)
def search_web(query: str) -> str:
    response = requests.get(f"https://example.com/search?q={query}")
    soup = BeautifulSoup(response.text, 'html.parser')
    
    # タイトルとスニペットだけ抽出
    results = []
    for item in soup.select('.result')[:5]:  # 上位5件だけ
        title = item.select_one('h3')
        snippet = item.select_one('.snippet')
        if title and snippet:
            results.append(f"タイトル: {title.text}\n概要: {snippet.text[:200]}")
    
    return "\n\n".join(results) if results else "結果が見つかりませんでした"

目安として、一つのツール結果は 5,000〜10,000トークン以内(日本語で約10,000〜20,000文字以内)に収めるようにすることをおすすめします。

2. tool_use_id が一致していない

これも意外と多いミスです。Claude が返した tool_use ブロックには id フィールドがあり、その ID を tool_result の tool_use_id に正確に指定しなければなりません。

# Claudeの応答から tool_use ブロックを取得した場合
response = anthropic.messages.create(...)
 
# ❌ IDをハードコードしたり、省略する
tool_results = [{
    "type": "tool_result",
    "tool_use_id": "toolu_01",  # ハードコードは危険
    "content": result_content
}]
 
# ✅ Claudeが返したIDをそのまま使う
for block in response.content:
    if block.type == "tool_use":
        tool_result = {
            "type": "tool_result",
            "tool_use_id": block.id,  # ← Claudeが返したIDをそのまま使う
            "content": str(tool_output)
        }

特に複数のツールが同時に呼ばれる場合(parallel tool use)、それぞれの id を正しく対応させる必要があります。

3. content フィールドの型が間違っている

tool_result の content フィールドには文字列か、画像などを含む配列を指定します。None や数値をそのまま渡すと受け付けられないことがあります。

# ❌ None や数値をそのまま渡す
"content": None
"content": 42
 
# ✅ 必ず文字列に変換する
"content": str(result) if result is not None else "ツールの実行結果がありませんでした"

エラーが発生した場合も空文字ではなく、エラーを示す文字列と is_error: true を使いましょう。

# ツールがエラーを返した場合の正しい書き方
{
    "type": "tool_result",
    "tool_use_id": block.id,
    "content": "エラー: データベースへの接続がタイムアウトしました",
    "is_error": True  # これでClaudeはエラーを認識してリカバリを試みる
}

4. ネットワーク・タイムアウト問題

ツールの実行に時間がかかりすぎると、API接続がタイムアウトすることがあります。特に外部APIを呼び出すツールや、大きなファイルを処理するツールは注意が必要です。

import anthropic
import httpx
 
# タイムアウトを明示的に設定する
client = anthropic.Anthropic(
    http_client=httpx.Client(timeout=60.0)  # 60秒に延長
)

ツール自体の実行時間が長い場合は、処理を分割するか、非同期処理を検討してください。

5. メッセージ履歴の形式が崩れている

会話を続けていくうちに、messages 配列の構造が正しくなくなることがあります。tool use を使う場合、メッセージの順番と形式に厳密なルールがあります。

# 正しいメッセージ履歴の構造
messages = [
    # 1. ユーザーのメッセージ
    {"role": "user", "content": "東京の天気を教えて"},
    
    # 2. Claudeのツール呼び出し応答
    {"role": "assistant", "content": [
        {"type": "text", "text": "天気を調べます。"},
        {"type": "tool_use", "id": "toolu_01", "name": "get_weather", "input": {"city": "Tokyo"}}
    ]},
    
    # 3. ツール結果(user ロールで送る)
    {"role": "user", "content": [
        {"type": "tool_result", "tool_use_id": "toolu_01", "content": "東京: 晴れ、25°C"}
    ]},
    
    # 4. 次のメッセージ...
]

assistant のメッセージの後に必ず user のツール結果を挟まないと、このエラーが出やすくなります。

デバッグ手順のまとめ

このエラーで詰まったときは、次の順番で確認してみてください。

まず tool_use_id の一致を確認します。Claude が返した ID と送信している ID が完全に一致しているかを print で確認しましょう。次に結果のサイズを確認します。len(result_content) を出力して、文字数が異常に多くないかチェックします。そして content の型を確認します。type(result_content) が str であることを確認しましょう。最後にメッセージ配列の構造を確認します。role の順番と content の形式が正しいかを見直します。

よくある疑問

Q. このエラーは Claude の側のバグですか?

多くの場合、実装側の問題です。ただし、まれに Claude 側の一時的な問題でも出ることがあります。同じコードで再試行して成功するなら、一時的な問題の可能性が高いです。

Q. stream モードでも同じエラーが出ます。対処法は変わりますか?

基本的な原因は同じです。ただし stream モードでは MessageStreamEvent のハンドリングが複雑になるので、まず非 stream モードで動作確認してから stream に切り替えることをおすすめします。

最後に

「tool result could not be submitted」は、メッセージのひとこと見ただけでは何が悪いのか分かりにくいエラーです。ただ、上記のパターンのいずれかに当てはまることがほとんどなので、順番に確認していけば解決できるはずです。

特に「ツール結果が大きすぎる」は見落としがちです。開発初期は小さなデータで動いていても、本番データになったとたんにエラーが出るケースをよく見るので、早めに結果サイズの制限を実装しておくことをおすすめします。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

◉ Claude.ai2026-04-09
Claude のファイル添付・画像認識が失敗する時の完全解決ガイド
PDFや画像をClaudeに添付しても読み込まれない・エラーになる問題を原因別に解決します。対応ファイル形式とサイズ制限の確認、ブラウザとアプリの設定、PDFと画像それぞれの対処、Failed to upload fileが繰り返し出るときに最初に確認する5箇所まで手順を追って解説します。
◉ Claude.ai2026-10-06
Pro を払ったのに無料のまま — 買った場所が Web かストアかで、見る画面も解約先も変わります
Claude Pro を払ったのに無料プランに見える、領収書が見つからない、解約ボタンがない。Web・Desktop で買った場合と iOS・Android のストアで買った場合を並べ、症状ごとに最初に開く画面を決めるための比較です。
◉ Claude.ai2026-10-03
使用量の上限が昼前に尽きた日、原因は送った回数ではなく一通の会話の長さでした
Pro や Max で「使用量の上限に達しました」が思ったより早く出たとき、Settings > Usage の二本のバー・その会話の往復数と添付・モデルと effort の順に見ています。昼前に止まった日の切り分けと、新しい会話へ移す線引きを書き残します。