Claude の API で使うモデルを新しい版に替えたら、次のエラーが出るようになった。あるいは、応答の文章が空のまま返ってくるようになった。原因はたいてい同じです。応答の1つ目(content[0])が文章ではなく、考えた過程のブロック(thinking ブロック)になったのです。

AttributeError: 'ThinkingBlock' object has no attribute 'text'

Python の SDK で response.content[0].text と書いていると、このエラーになります。JavaScript では同じ書き方で undefined が返り、エラーにならずに空の文章として流れていきます。厄介なのは、簡単な入力では先頭が文章のままなので、軽い入力の試験は通ってしまうことです。

この問題を3行で

起きること

先頭が文章でなくなる

主に重い入力で、応答の先頭に考えた過程のブロックが入る(軽い入力でも入ることがある)。content[0].text が壊れる。

原因

指定しなくても考える

Claude 5 以降のモデルは、thinking を書かなくても必要なときに考える。Claude 4 系は書かなければ考えない。

直し方

種類で探して読む

先頭を決め打ちせず、type が "text" のブロックを集めて読む。stop_reason も確かめる。

1. どんなときに起きるか

典型は「モデルの名前を替えるだけの移行」です。たとえば Claude Sonnet 4.6 から Claude Sonnet 5.5 へ、model の値だけを書き換えます。応答の形は同じだと考えて、ほかのコードは触りません。すると、次のことが起きます(3つ目は正しく書いたコードでも起きます)。

書き方起きること
Python の SDK で content[0].textAttributeError: 'ThinkingBlock' object has no attribute 'text' で止まる
JavaScript で content[0].textエラーにならず undefined になり、画面や保存先に空の文章が入る
文章のブロックを探して読む考える量が多く max_tokens に届くと、文章のブロックが1つも無いことがある

3つ目は、正しく書いたコードでも起きます。考えた過程に使ったトークンも max_tokens に数えられるので、上限が小さいと文章を書く前に打ち切られます。

2. 原因:Claude 5 以降は指定しなくても考える

Anthropic の文書「Thinking」には、リクエストに thinking を書かなかったときの動きがモデルごとに載っています。境目は Claude 5 です。

モデルthinking を書かないとき考えた過程の中身
Claude 5 以降(Opus 5.5・Sonnet 5.5・Haiku 5.5・Fable 5.1 など)考える(adaptive thinking)既定では空(display: "omitted")
Opus 4.8・Opus 4.7考えないthinking: {type: "adaptive"} を書いたときだけ考え、中身は既定では空("omitted")
Opus 4.6・Sonnet 4.6考えないthinking: {type: "adaptive"} を書いたときだけ考え、既定では要約が返る("summarized")

出典:Anthropic「Thinking」のモデル別の表と display の説明(2026年11月1日確認)。Opus 4.5・Sonnet 4.5・Haiku 4.5 は {type: "adaptive"} を受け付けず、考えさせるには {type: "enabled"} と budget_tokens を使います。

考えるかどうかは、モデルが入力ごとに決めます。文書「Steering thinking」は、簡単な事実の質問には thinking ブロックを付けずに答えることがあると説明しています。そのうえで、すべての応答が thinking ブロックから始まる前提でアプリの処理を組まないようにと注意しています。つまり、先頭が文章のときもあれば、考えた過程のときもあります。どちらかに決め打ちしたコードは、どこかで壊れます。

応答の中身は、次の図のように並びます。考えた過程の中身は既定では空ですが、ブロックそのものは返ってきます。

3. 実際に試した結果

筆者の環境で、Python の SDK(anthropic 1.14.0)を使って試しました(2026年11月1日)。4つのモデルに、thinking を書かない場合と {type: "adaptive"} を書いた場合で、軽い入力と重い入力を1回ずつ送っています。max_tokens は 8000 にしました。軽い入力は「日本の首都はどこですか。一言で答えてください。」で、重い入力は条件を5つ満たす4桁の整数をすべて求める問題です。

モデルthinking の指定軽い入力の content重い入力の content
Sonnet 4.6書かないtexttext
Sonnet 4.6adaptivetextthinking だけ(上限に到達)
Haiku 5.5書かないtextthinking だけ(上限に到達)
Haiku 5.5adaptivetextthinking だけ(上限に到達)
Sonnet 5.5書かないtextthinking → text
Sonnet 5.5adaptivetextthinking → text
Opus 5.5書かないtextthinking → text
Opus 5.5adaptivethinking → textthinking → text

赤字は content[0].text が AttributeError: 'ThinkingBlock' object has no attribute 'text' になった組み合わせ。各1回の結果で、同じ入力でも回によって考えるかどうかは変わりえます。

読み取れることは3つです。

1つ目に、Claude 5 以降は thinking を書かなくても重い入力で考えました。Sonnet 4.6 では、書かなければ先頭は文章のままでした。モデル名を替えるだけで応答の形が変わることを、文書のとおりに確かめられました。

2つ目に、軽い入力ではほとんどの組み合わせで先頭が文章でした。試験を軽い入力だけで組むと、この問題は見つかりません。一方で、Opus 5.5 に adaptive を書いた回は、軽い入力でも考えていました。Claude 5 以降では thinking を書かないことと adaptive を書くことは同じ設定なので、この違いは回ごとの揺れと考えられます。「軽ければ考えない」とは言い切れません。

3つ目に、上限に届くと文章が1つも返りませんでした。Haiku 5.5 の重い入力は、thinking を書かない回も adaptive の回も 8000 トークンを考えることに使い切り、文章のブロックがありませんでした。Sonnet 4.6 も adaptive の回で同じく上限に届きました。Claude 5 以降では考えた過程の中身も既定で空なので、利用者には何も表示されないのに、出力トークンの料金はかかります。

4. 直し方

直し方は、先頭を決め打ちせず、種類が文章(type が "text")のブロックを集めて読むことです。あわせて stop_reason を確かめ、上限で打ち切られた応答を正常な答えとして扱わないようにします。

Python

import anthropic

client = anthropic.Anthropic()
response = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=16000,
    messages=[{"role": "user", "content": prompt}],
)

# 先頭を決め打ちしない:文章のブロックだけを集める
text = "".join(b.text for b in response.content if b.type == "text")

if response.stop_reason == "max_tokens":
    # 上限で打ち切られた。text が空のこともある
    raise RuntimeError("max_tokens に届いた。上限を上げるか、考える量を減らす")
if response.stop_reason == "end_turn" and not text:
    # ツールを使う流れでは stop_reason が "tool_use" で、text が空でも正常
    raise RuntimeError("文章のブロックが無い")

TypeScript

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();
const response = await client.messages.create({
  model: "claude-sonnet-5-5",
  max_tokens: 16000,
  messages: [{ role: "user", content: prompt }],
});

// 型で絞り込んでから text を読む
const text = response.content
  .filter((b): b is Anthropic.TextBlock => b.type === "text")
  .map((b) => b.text)
  .join("");

if (response.stop_reason === "max_tokens") {
  throw new Error("max_tokens に届いた。上限を上げるか、考える量を減らす");
}
// ツールを使う流れでは stop_reason が "tool_use" で、text が空でも正常
if (response.stop_reason === "end_turn" && text === "") {
  throw new Error("文章のブロックが無い");
}

TypeScript の SDK では、content の要素は文章・考えた過程・ツールの呼び出しなどの型の和になっています。content[0].text をそのまま書けば、本来は型の確認で止まります。ただし as で型を決め打ちしていると、この誤りは見逃されます。

max_tokens は考える分も含めて決める

文書「Steering thinking」は、max_tokens が考えた過程と答えの文章を合わせた上限だと説明しています。考えない前提で決めた上限は、難しい入力では小さすぎることが多い、とも書いています。stop_reason: "max_tokens" が出たときの直し方は2つです。

上の例の 16000 は目安の値です。筆者の実測では 8000 でも考えるだけで使い切る例がありました。本番の値は、重い入力を流して、応答の usage.output_tokens_details.thinking_tokens(考えに使ったトークン数)を見て決めます。

  • 上限を上げる:打ち切られた入力で、考えることが答えの質に効いているとき
  • effort(工数)を下げる:考えすぎているだけで、答えの質は変わらないとき(effort は output_config.effort で決める)

会話を続けるときは、考えた過程のブロックも返す

会話の履歴に応答を足すときは、文章だけを抜き出さず、content をそのまま返します。とくにツールを使う流れでは、考えた過程のブロックにツールを呼んだ理由が入っています。文書は、受け取ったブロックを書き換えずに返すよう求めています。書き換えたブロックは 400 エラーで拒まれます。表示に使う文章と、履歴に返す content は分けて持つのが安全です。

5. 考えるのを止めれば済むか

「考えた過程が邪魔なら止めればよい」と考えたくなりますが、止められるかどうかはモデルによって違います。thinking: {type: "disabled"} の扱いは次のとおりです。

モデル{type: "disabled"}
Opus 5.5・Fable 5.1・Fable 5400 エラー(止められない)
Sonnet 5.5400 エラー(代わりに {type: "between_tools"} なら、effort が high 以下で最初に考えるのを止められる)
Haiku 5.5・Opus 5止められる(effort が high 以下のときだけで、xhigh・max では 400 エラー)
Sonnet 5止められる

出典:Anthropic「Thinking」(2026年11月1日確認)。モデルが受け付けるかは Models API の capabilities.thinking.types.disabled.supported でも確かめられます。effort の既定は Opus 5.5・Haiku 5.5 が medium、ほかの多くのモデルが high なので、既定のままなら「high 以下」の条件は満たします。

止められるモデルでも、止めれば難しい入力での答えの質が下がりえます。そして、モデルを替えるたびに同じ問題が戻ってきます。根本の直し方は、どんな並びの応答でも読めるコードにすることです。考える量を抑えたいときは、まず effort を下げます。Anthropic の文書によると、Sonnet 5.5 はシステムプロンプトで考えを減らすよう頼んでも確実には減らず、Haiku 5.5 は直接答えるよう指示しても考えるのを止めませんでした(Anthropic の試験)。どちらも effort で調整します。

6. 試験で見落とさないために

この問題は、軽い入力の試験をすり抜けます。モデルを替えるときは、次の順で確かめると見落としにくくなります。

  1. コードの中の content[0] を探す:content[0]・content[-1]・.content[0].text のように、位置で読んでいる所を、本番のコードだけでなく試験やログを出す処理まですべて洗い出す
  2. 重い入力を試験に入れる:本番で最も長い入力・最も難しい処理を試験の入力に加える(軽い入力だけでは先頭が文章のままで、壊れた所が見えない)
  3. 考えた過程が先頭に来る応答を、作り物で流す:API を呼ばない単体の試験に、[thinking, text] の並びと、thinking だけで stop_reason が "max_tokens" の応答を用意して読ませると、モデルが考えるかどうかに左右されずに確かめられる
  4. 切り替えは一部から:全部を一度に替えず、一部の処理から新しいモデルに移し、空の文章や例外の数を見てから広げる

⚠️ 複数のサービスや担当者でまとめてモデルを替えるときは、切り替えの依頼文に「応答の先頭が文章とは限らない。種類で探して読む」と一行足しておきます。名前を替えるだけの作業だと思われやすく、各担当が自分で気づくのを待つと、軽い入力の試験を通ったまま本番で壊れます。

モデルを替えるときに確かめることは、これだけではありません。前の世代からの移行で変わった点は、「Claude Opus 4.7 への移行ガイド」と「Claude Fable 5.1 の破壊的変更と移行」にまとめています。API の effort は Anthropic の文書「Effort」に、Claude Code での effort の選び方は「Claude Code の工数(effort)設定」にあります。

まとめ

  • AttributeError: 'ThinkingBlock' object has no attribute 'text' は、応答の先頭が考えた過程のブロックになったときに、content[0].text で文章を読もうとして起きる
  • Claude 5 以降のモデルは、thinking を書かなくても必要なときに考えるので、Claude 4 系からモデル名を替えるだけで応答の形が変わる
  • 軽い入力では先頭が文章のままのことが多く、軽い試験は通ってしまう
  • 直し方は、type が "text" のブロックを集めて読み、stop_reason が "max_tokens" かどうかも確かめること
  • 考えるのを止められないモデルもあるので、止めることより、どんな並びでも読めるコードにすることが根本の直し方

FAQ

Q. thinking を一度も指定していないのに、なぜ thinking ブロックが返るのですか?

A. Claude 5 以降のモデルは、thinking を書かなくても adaptive thinking が有効で、必要と判断した入力で考えるからです。考えた過程の中身は既定では空ですが、ブロックそのものは応答に入ります。Claude Opus 4.8・Sonnet 4.6 などの Claude 4 系は、書かなければ考えません。

Q. 文章のブロックが1つも無い応答が返るのはなぜですか?

A. 考えた過程に使ったトークンも max_tokens に数えられ、文章を書く前に上限に届いたからです。stop_reason が "max_tokens" になっているはずです。上限を上げるか、effort を下げて考える量を減らします。

Q. 考えた過程の中身を読みたいときは?

A. thinking: {type: "adaptive", display: "summarized"} を指定すると、考えた過程の要約が返ります。Claude 5 以降の既定は "omitted"(中身は空で、署名だけが入る)です。どちらでも、料金は考えた分のトークン全体にかかります。

更新の記録

  • 2026年11月1日初版。Anthropic の文書「Thinking」「Steering thinking」を確認し、筆者の環境で4つのモデルの応答の並びを試して作成。

出典