Claude Media
Browser use toolのエラーハンドリング — executor側のis_error規約

Browser use toolのエラーハンドリング — executor側のis_error規約

Browser use toolでexecutorが失敗をどう返すか、navigateのスキーム拒否やバッチアクション停止の実例から読み解きます。

Browser use toolのエラーはexecutorが形にする

Browser use toolは、Claudeがブラウザを操作するためのbrowser_toolset_20260801というクライアントツールセットです。navigateやleft_clickなど27個のメンバーツールを既定で宣言でき、javascript_execのような残り4つはconfigsで有効化した場合だけ追加されます(最大31個)。実行そのものは常にアプリケーション側のexecutorが担います。Anthropicのサーバーはtool_useブロックを返すだけで、ブラウザは動かしません。

この構造では、呼び出しが失敗したときにClaudeへ何を返すかがexecutor側の設計事項になります。失敗した呼び出しは、通常のエラー結果として返すのが公式ドキュメントの基本形です。

基本形

エラー結果の基本形

  • 付けるもの

    is_error: true、何が起きたかを書いたtext content、呼び出しと同じtoolset_nameのechoの3点です。

  • 付けないもの

    browser_stateブロック。is_error: trueの結果に載せると、リクエストがinvalid_request_errorで弾かれます。

  • 返す相手

    実行しなかった呼び出しも含め、tool_use1つにつきtool_resultを1つ返します。

形そのものは単純で、難しいのは文言の書き方と、navigateのスキーム拒否のような個別ケースの扱いです。

失敗が返る場所は2つある

executorが組み立てるis_errorの結果と、APIが会話の前に突き返す400は、別の層の失敗です。どちらで起きた問題かを先に切り分けると、直す場所が決まります。

くらべる

エラーの出どころで直す場所が変わる

Claudeに届く

executorが返すis_error

ページが開かない、参照が見つからない、メンバーが未実装といった実行時の失敗です。Claudeは文言を読んで次の手を決めます。直すのは文言の具体性です。

Claudeに届かない

APIが返すinvalid_request_error

tool_resultの形が規約に反したときの拒否で、Claudeが動く前に起きます。直すのは文言ではなく、フィールドとブロックの組み立てです。

後者の具体的な原因は、後半の「リクエスト自体が拒否される400エラー」の表にまとめています。

セキュリティ上の推奨事項の中でも、navigateハンドラーの実装は具体的な規約を伴います。公式ドキュメントは次の4点を挙げています。

  1. 履歴操作のキーワード"back"・"forward"・"reload"を受け付ける
  2. スキームの無いURLはhttps://として扱う
  3. URLをパースしたうえで、http・https以外のスキーム(javascript:・file:・data:・chrome:など)をエラー結果で拒否する
  4. スキームの判定は文字列の前方一致ではなく、URLパーサーで行う

3番目と4番目は対になっています。文字列マッチだけで判定すると、細工されたURLがスキーム拒否をすり抜ける余地が残ります。APIはClaudeが開くURLをフィルタしないため、拒否できるのはexecutor側だけです。実際に拒否したときのエラー結果は次の形になります。

{
  "type": "tool_result",
  "tool_use_id": "toolu_01LeUTyqkhRxBFq1QTG3pkwN",
  "toolset_name": "browser",
  "is_error": true,
  "content": "Error: Navigation refused. Only http and https URLs are allowed."
}

文言はClaudeが次に何をするかを左右する

エラーのtext contentは、単なる通知ではなくClaudeが読んで行動を調整する入力です。公式ドキュメントはError: navigation failedのような素っ気ない文言と、Error: Navigation to https://example.com/status timed out after 30 seconds. The page may be unavailable.のような具体的な文言を対比しています。後者だけがClaudeにとって行動の手がかりになるという立場です。

失敗したURL、待った秒数、ページ側に原因がありそうかまで書き込むと、Claudeは再試行するか別の手段に切り替えるかを判断できます。何が起きたかに加えて、次にどう解釈するかまで書くのが実務上のポイントです。一般的なツールでの文言設計はtool_resultのis_errorでエラーを正しく伝える書き方にまとめています。

4つの典型パターンと返す文言

スキーム拒否以外にも、公式ドキュメントは3つの典型的な失敗パターンを例示しています。いずれもis_error: trueとtoolset_name: "browser"は共通で、contentの文言だけが変わります。

ケース返すcontentの例
スキーム拒否返すcontentの例Error: Navigation refused. Only http and https URLs are allowed.
古い・存在しない要素参照返すcontentの例Error: ref_3 is stale or not found on the current page. Re-read the page to get fresh references.
無効化・未実装のメンバー返すcontentの例Error: javascript_exec is not enabled in this environment.
バッチ内の後続呼び出し返すcontentの例Not executed: an earlier action in this turn failed.(文言固定)

「無効化されたメンバー」は、configsで無効にしたメンバーをClaudeが呼んでしまったケースです。client toolsetsの仕様では、無効化したメンバーはClaudeに見えるツール一覧から除かれます。それでもClaudeが名指ししてきた場合は、呼び出しを捨てずにエラーのtool_resultで答えます。

「古い要素参照」のref_3は、read_pageやfindがexecutorの側で割り当てた参照です。見つからない、または古い参照を受け取ったら、文言の後半にあるとおり、ページを読み直して新しい参照を取るようClaudeに伝えます。

バッチアクションは最初の失敗で打ち切る

1つのターンで複数のメンバー呼び出しが並ぶ「バッチアクション」では、失敗の伝播ルールが単発呼び出しと異なります。

処理順

バッチ内で失敗が起きたときの処理

  1. 1

    記載順に実行する

    並行ではなく、tool_useが並んだ順に1つずつ実行します。

  2. 2

    最初の失敗で止める

    失敗した呼び出しには、executor自身の具体的なエラー文言を返します。

  3. 3

    残りを固定文言で埋める

    それ以降の呼び出しはすべてis_error: trueとNot executed: an earlier action in this turn failed.で答えます。

  4. 4

    省略せずに全件返す

    実行しなかった呼び出しのtool_resultも、同じuserメッセージに含めます。

検索ボックスをクリックし、文字を入力し、Enterキーを押す3つの呼び出しが1ターンにまとまっている場面を考えます。最初のクリックが古い参照エラーで失敗すると、続くtypeとkeyは実行されません。2つにはhalt文言のエラー結果が返ります。

Claudeは3つの呼び出しを「クリックが成功した前提」で組み立てています。実行しなかった呼び出しにも結果を返すのは、会話の整合性を保つためです。並列呼び出しの一部が失敗する一般的なケースは並列ツール呼び出しが一部失敗したときのis_errorの返し方でも扱っています。

この規約に沿ったexecutorの骨組みを、Pythonで書くと次のようになります。

HALT = "Not executed: an earlier action in this turn failed."
 
def run_batch(blocks, handlers):
    results, failed = [], False
    for b in blocks:  # tool_useを記載順に処理する
        base = {"type": "tool_result", "tool_use_id": b.id,
                "toolset_name": "browser"}
        if failed:
            results.append({**base, "is_error": True, "content": HALT})
            continue
        try:
            if b.name not in handlers:
                raise ExecutorError(
                    f"{b.name} is not enabled in this environment.")
            results.append({**base, "content": handlers[b.name](b.input)})
        except ExecutorError as e:
            failed = True
            results.append({**base, "is_error": True,
                            "content": f"Error: {e}"})
    return results

エラー側のブロックにbrowser_stateを載せない点は、is_errorの分岐が自然に守ってくれます。成功側のハンドラーがbrowser_stateを組み立てる処理は、この骨組みの外に置いています。ExecutorErrorは手元の例外クラスで、ブラウザ自動化ライブラリの失敗をこの型に包む想定です。

tab_idが不正なときもエラー結果で返す

switch_tabとclose_tabのtab_idはClaudeが入力として渡します。APIは成功結果のテキストにこの値を埋め込むため、tab_idにはbrowser_stateと同じ制限がかかります。4,096文字以内であること、制御文字や改行を含まないこと、Unicodeの行区切り・段落区切りを含まないことです。

この制限に反するtab_idが来たら、browser_stateを組み立てて返してはいけません。エラー結果で答えます。switch_tabのinput.tab_idはAPIが結果のテキストに差し込むため、制限を超えた値はbrowser_stateの形では返せません。

ダウンロード失敗はis_errorでは報告しない

すべての失敗がis_errorとcontentの組み合わせで表現されるわけではありません。クリックやナビゲーションがファイルダウンロードを開始し、そのダウンロードが失敗・キャンセルされた場合はdownload_failedという別の経路で報告します。これは成功した呼び出しのbrowser_stateブロックが持つstate_changes配列に載せるイベントで、download_id・url・任意のerrorフィールドを持ちます。

ここで公式ドキュメントが釘を刺しているのが、is_error: trueの結果にstate_changesを送ってはいけないという規約です。ダウンロードの失敗がエラー呼び出しの最中に起きた場合も、そのstate_changesは当の結果には乗せません。次に成功した結果まで持ち越して報告します。browser_stateをエラー結果に付けない規約と、この持ち越しルールは同じ原則の裏表です。

download_id・url・path・errorには、4,096文字以内で制御文字を含めないという上限があります。ブラウザが返す生のエラー文字列は、転記する前にこの上限内へ整形します。urlはリダイレクトを経たあとの最終URLで、署名付きのクエリ文字列に認証情報が含まれることがあります。Claudeの文脈に入れたくないクエリパラメータは、報告前に落とします。

リクエスト自体が拒否される400エラー

executorが返すis_errorとは別に、リクエストの形が規約に反すると、Claudeが応答する前にAPIがinvalid_request_errorで弾きます。整形ルール全般はtool_resultとtool_useの400エラーで扱った内容と地続きです。Browser use toolでは、次の組み合わせがこのエラーになります。

何を送ったか規約
ツールセットのエントリにname・strict: true・input_examples・defer_loadingを付ける、2つ目のbrowserツールセットを置く、browserやメンバーを名指しするtool_choiceを使う規約クライアントツールセットが受け付けない指定
toolset_nameのechoが無い、または値が違う。メンバー呼び出しでない結果にtoolset_nameを付ける規約メンバーの結果にだけ、呼び出しと同じ値を付ける
text・image・browser_state以外のブロックを含む規約メンバー結果が許すブロック型はこの3種類
前ターンのメンバー呼び出しに対応するtool_resultが無い規約実行しなかった呼び出しにも結果を返す
is_error: trueの結果へのbrowser_state、空のstate_changes、同じdownload_idの重複規約browser_stateの規約違反。何も報告しないときはブロックや配列を省く
成功したnew_tab・switch_tab・close_tab・list_tabsの結果がbrowser_state1つちょうどではない規約タブ管理系メンバーの結果はbrowser_state1つだけ
画像がモデルの画像サイズ上限を超える規約APIは自動で縮小しない
browser_toolset_20260801に対応しないモデルを指定する規約対応モデルは後述

画像の行には補足があります。リクエストに20枚を超える画像が含まれるときは、より厳しいサイズ上限が適用されます。数えるのは過去の結果に含まれるscreenshotやzoomの画像も含めた枚数です。画像の扱いはモデルの画像サイズ上限に従い、返す前にexecutor側でリサイズしておきます。

toolset_nameのechoは、成功結果にもエラー結果にも共通する規約です。Browser use toolのメンバー呼び出しに返すtool_resultは、通常のカスタムツールへのtool_resultと違い、この値を必ず持ちます。通常の形で整えた結果をそのまま返すと、ここで400になります。

Computer use toolとの共通点と違い

Browser use toolとComputer use toolはどちらもAnthropic定義のクライアントツールセットです。toolset_nameのechoや、最初の失敗でバッチを止める規約など、エラー処理の骨格は共通です。Computer Useツールを自前実装する最小構成の実装パターンも、骨格はそのまま流用できます。

違いは2点あります。1つは打ち切り後の文言で、両ページは別の固定文を定めています。

ツールセットtoolset_nameバッチ後続の固定文言
Browser usetoolset_namebrowserバッチ後続の固定文言Not executed: an earlier action in this turn failed.
Computer usetoolset_namecomputerバッチ後続の固定文言Not executed: an earlier computer action in this turn failed.

toolset_nameの値だけ差し替えて文言を使い回すと、Computer use側の固定文と食い違います。もう1つはbrowser_stateで、これはブラウザのタブ状態を追跡するBrowser use toolだけの仕組みです。Computer use toolの結果には登場しません。

両ツールセットはscreenshotやkeyのようにメンバー名が重なります。同じリクエストに両方を宣言したときは、nameだけでなくtoolset_nameとの組で呼び出しを振り分けます。

対応モデルとプラットフォームの範囲

エラーハンドリングを実装する前提として、Browser use toolを呼べる環境そのものが限られています。対応モデルは次の9つです。

  • claude-fable-5-1・claude-mythos-5-1
  • claude-fable-5・claude-mythos-5
  • claude-opus-5-5・claude-opus-5
  • claude-sonnet-5-5・claude-sonnet-5
  • claude-opus-4-8

利用できるプラットフォームはClaude APIとGoogle Cloudの2つです。Claude Platform on AWS・Amazon Bedrock・Microsoft Foundryではこの日付付きツールセットを使えません。Claude Managed Agentsのツールとしては提供されていません。対応外のモデルを指定した場合は、executor側のエラーではなくAPI側のinvalid_request_errorとして返ります。

まとめ

toolset_nameのechoとbrowser_stateの省略という2点は、エラー結果のテンプレートに固定しておく項目です。ここを外すとClaudeに届く前に400で止まるため、文言の工夫に進むのはその後になります。navigateのスキーム拒否とバッチの打ち切りは、この土台の上に乗る個別規約として実装します。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool
  2. platform.claude.com/docs/en/agents-and-tools/tool-use/tool-reference
  3. platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool
この記事を共有:XはてブLinkedIn