CLAUDE LABEN
FORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられていますFORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられています
記事一覧/API & SDK
API & SDK/2026-05-22上級

Claude API の tool_result could not be submitted が再発しないための回復ハンドラ設計

Claude API でエージェントを長時間動かしていると、ある日突然 'tool_result could not be submitted' が連発し始めることがあります。再試行しても直らない、ストリーミング途中で死ぬ、そして次のセッションでもまた出る — 個人開発で運営している6サイトの自動投稿パイプラインで実際に踏み抜いた4種類の原因と、TypeScript で書いた回復ハンドラの実装を整理しました。

claude-api81tool-use21error-handling10agent-recoveryproduction87

プレミアム記事

自動投稿パイプラインを Claude API で組んで運用していると、ある日突然このエラーが連発し始めます。tool_result could not be submitted。一度出るとそのセッションは打ち切られ、リトライしても直らず、しばらくすると別のエージェントでも同じことが起きる。2014年からアプリ事業をやってきた人間として、個人開発で運営している6サイトのコンテンツ自動投稿パイプライン(Claude Lab・Gemini Lab・Antigravity Lab・Rork Lab・Lacrima・Mystery)で、ある夜に4サイト連続でこの症状にぶつかり、夜が明けるまで原因を切り分けていたことがあります。

このエラーは Anthropic の公式ドキュメントには再現条件がほとんど書かれていません。ただ、発生メッセージはひとつでも、実態は4種類のまったく別の根本原因が同じエラー文に集約されているだけ — というのが半年運用してわかったことです。リトライで直るのは1種類だけで、残りの3種類は API リクエストの組み立てを変えないと永遠に再発します

ここでは、本番運用中のパイプラインで実際に観測した4種類の発生パターンと、それぞれに対するリカバリの実装を、TypeScript のコードと一緒に整理します。

発生する4種類の根本原因

エージェントを長く動かしていると tool_result could not be submitted は次の4種類のいずれかで発生します。エラーメッセージ自体に区別はないので、API レスポンスの周辺情報と tool_use_id の対応関係から手動で切り分けます。

  1. tool_use_id と tool_result の対応が壊れている: 前のターンで Claude が tool_use を返したのに、こちらが返す tool_resulttool_use_id が一致していない、あるいは一部の tool_use に対する結果が抜けている
  2. メッセージ配列の順序が tool_use → tool_result の直後ペアになっていない: 間に text ブロックを挟んでしまった、あるいは tool_result のメッセージを assistant ロールで送ってしまった
  3. ストリーミング途中で接続が切れて parallel tool_use が中途半端になっている: 5個並列で tool_use が返ってきたうち3個まで実行した時点でクライアントが落ち、次回再開時に残り2個を実行する前に新しい user メッセージを送ってしまった
  4. tool_result の content が過大(おおむね 200KB 超): 1件あたりの返り値が大きすぎて API 側でリジェクトされています。これは別エラーで返ることもあるが、parallel tool_use の中の1件だけが超過しているケースでは could not be submitted に統合されて返ってくる

私が運用している自動投稿パイプラインでの発生比率は、ざっくり 1番目 50% / 2番目 20% / 3番目 25% / 4番目 5% でした。1番目だけはコード上のバグ、2番目は SDK の使い方の誤解、3番目はストリーミング処理の設計ミス、4番目はツール返り値の圧縮不足です。リトライで直るのは2番目だけで、それ以外は 送信するメッセージ配列そのものを書き換えないと根治しません

tool_use_id 不一致の検出と修復

最も多いのがこれです。Claude が parallel tool_use で複数の tool_use_id を返してきたとき、こちらが tool_result を返す側で1個でも tool_use_id を取り違えると、API は丸ごと拒否してきます。

import Anthropic from "@anthropic-ai/sdk";
import type { MessageParam, ToolUseBlock } from "@anthropic-ai/sdk/resources/messages";
 
interface ToolInvocation {
  id: string;          // tool_use_id
  name: string;
  input: unknown;
  result?: string;
  error?: string;
}
 
/**
 * 直前の assistant メッセージから tool_use ブロックを全て抽出し、
 * tool_use_id をキーにした Map を作る。実行結果はこの Map に書き戻す。
 */
function extractPendingToolUses(messages: MessageParam[]): Map<string, ToolInvocation> {
  const last = messages[messages.length - 1];
  if (last.role !== "assistant" || typeof last.content === "string") {
    return new Map();
  }
  const pending = new Map<string, ToolInvocation>();
  for (const block of last.content) {
    if (block.type === "tool_use") {
      const tu = block as ToolUseBlock;
      pending.set(tu.id, { id: tu.id, name: tu.name, input: tu.input });
    }
  }
  return pending;
}
 
/**
 * tool_result メッセージを組み立てる前に、pending と完全一致するか検証する。
 * 1件でも漏れがあれば、空の結果("tool execution skipped" 等)で穴埋めする。
 * 余計な tool_use_id を含めないことも同じくらい重要。
 */
function buildToolResultMessage(
  pending: Map<string, ToolInvocation>,
  executed: Map<string, ToolInvocation>
): MessageParam {
  const content = [];
  for (const [id, inv] of pending) {
    const done = executed.get(id);
    if (done) {
      content.push({
        type: "tool_result" as const,
        tool_use_id: id,
        content: done.result ?? "",
        is_error: Boolean(done.error),
      });
    } else {
      content.push({
        type: "tool_result" as const,
        tool_use_id: id,
        content: "tool execution skipped (client recovery)",
        is_error: true,
      });
    }
  }
  return { role: "user", content };
}

この pendingexecuted の差分検証を、API に送信する直前に必ず通すようにしました。私のパイプラインでは、これだけで tool_result could not be submitted の発生件数が月 80 件規模から月 5 件以下まで落ちました。発生率にして 95% 削減です。コストにすると、1件のリトライで Claude Sonnet 4.6 を平均 18,000 入力トークン消費していたので、削減できた API コストは月あたりおよそ ¥4,500 相当でした。

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

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
tool_result could not be submitted の4種類の発生パターン(ID 不一致/順序破綻/ストリーム中断/コンテンツ過大)を、API のレスポンス例と一緒に切り分けられるようになります
リトライではなく状態復元で対処する TypeScript の回復ハンドラを、本番運用中の自動投稿パイプラインのコードベースから抜粋して持ち帰れます
個人開発の自動運用で実際に観測した発生頻度と、各原因に対する根治コスト・再発防止策の温度感を共有します
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

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

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

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

関連記事

API & SDK2026-06-28
弱いモデルへ静かに落ちる方がエラーより怖い — Claude API のモデル降格に「下限」を設ける設計
無人運用のパイプラインでモデルが使えなくなったとき、弱いモデルへ自動で落ちる実装は危険です。タスクごとの能力契約と降格予算で「どこまで落ちたら止めるか」を決める設計を、個人開発の自動運用の実体験から解説します。
API & SDK2026-05-26
Claude API の構造化レスポンスを本番で安定させる — tool_use と JSON Schema、多層検証の実装メモ
Claude API の応答を JSON で受け取る実装は数行で書けますが、本番運用では「形は正しいが意味が壊れている」レスポンスにどう備えるかが分かれ目になります。tool_use・JSON Schema・ドメイン検証を組み合わせた多層パイプラインを、壁紙アプリの分類処理での実体験を交えて整理しました。
API & SDK2026-05-09
Claude API の 400/422/529 を“呼ぶ前”に消す5層プリフライト設計 — 月数百件の失敗呼び出しをゼロにした実装
Claude API の 400/422/529 エラーを“呼ぶ前”に止める5層プリフライト設計を、TypeScript の完全実装と運用1ヶ月分の数値でまとめました。失敗呼び出しのコスト・リトライ・通知ノイズを同時に削減できます。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →