◉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 に渡したフォルダの先頭に、十行の約束ファイルを置いてみました
記事一覧/API & SDK
⬡ API & SDK/2026-05-22中級

Claude の『このモデルは現在利用できません』が出る時に効くモデル選択フォールバックの設計

Claude API で『このモデルは現在利用できません(this model is currently unavailable)』と返ってきたとき、529 Overloaded やレート制限と同じ扱いにすると遠回りになります。エラーの種類を SDK の例外クラスで見分け、モデル ID をリクエスト単位で切り替えるフォールバックの実装と、思い込みで書きやすい落とし穴をまとめました。

claude-api83model-availabilityfallback8error-handling10troubleshooting61

夕方にデプロイしたばかりの定型処理から、「このモデルは現在利用できません」というエラーが返ってきたことがありました。リトライしても結果は同じで、私は同じ呼び出しを十回ほど繰り返し、ログだけを無駄に太らせてしまいました。

あとから気づいたのは、リトライは「同じ条件をもう一度試す」操作だということです。拒否されたのがモデル ID そのものなら、待っても条件は変わりません。 待つのではなく、指定を切り替える設計が要るのだと思います。

ここからは、そのエラーを 529 や 429 から切り離して扱う方法と、リクエスト単位でモデルを切り替えるフォールバックの実装をお伝えします。あわせて、以前の私が思い込みで書いて後から直した箇所も正直に残しておきます。

このエラーは何を意味しているのか

529 Overloaded や 429 Rate Limit は、サーバーの混雑や自分の使いすぎが理由です。しばらく待てば通るので、SDK の自動再試行に任せるのが筋になります。

一方、このエラーは「いま指定したモデル ID を、この経路では受け付けられない」という拒否です。待てば直ることもありますが、直らないこともあります。両者を同じ網で扱うと、混雑の最中にフォールバック先へ負荷を流し込んだり、逆に恒久的な拒否を延々とリトライしたりしてしまいます。

なお、エラー文面は経路(Anthropic 直、クラウド事業者経由)や時期によって変わります。この記事の判別ロジックは、文面の完全一致に頼らず、ステータスコードと SDK の例外クラスを軸にしています。ご自身の環境で実際に返ってきた応答を、一度ログで確かめていただければ幸いです。

出やすい場面を五つに分けて見る

私が見てきた範囲では、拒否の背景はおおむね次の五つに分かれます。発生割合の数字は取っていないので、頻度の順位づけはしません。

場面典型的な状況対処の向き
新モデルの公開直後新しい ID を指定したが、経路やリージョンによってまだ届いていない前世代のモデルへ切り替える
廃止済み・廃止間近の ID古い ID を固定で書き続けている廃止日を確認し、後継へ移す。移行前の保険としてフォールバックを持つ
クラウド事業者経由Bedrock や Vertex AI でリージョンごとに提供モデルが違うリージョンごとに候補リストを持つ
ID の書き間違い・別名の混在日付付き ID と別名を取り違えている起動時に ID の存在を一度確かめる
権限・プランの制約アカウントに許可されていないモデルを指定している切り替えでは直らない。通知して人が見る

表の最後の行がいちばん大事です。権限の拒否はフォールバックで隠してはいけません。切り替えて動いてしまうと、本来は気づくべき設定の不一致が見えなくなるからです。

モデル ID のフォールバック表を持つ

最初に作るのは、用途ごとの「優先モデル」と「落ちたときの代役」の表です。

type ModelTier = "frontier" | "balanced" | "fast";
 
interface ModelFallbackChain {
  primary: string;
  fallbacks: string[];
}
 
// ID は実在するものだけを書く。書き換え前に公式のモデル一覧で確認してください
const FALLBACK_CHAINS: Record<ModelTier, ModelFallbackChain> = {
  frontier: {
    primary: "claude-opus-4-6",
    fallbacks: ["claude-sonnet-4-6"],
  },
  balanced: {
    primary: "claude-sonnet-4-6",
    fallbacks: ["claude-sonnet-4-5", "claude-haiku-4-5-20251001"],
  },
  fast: {
    primary: "claude-haiku-4-5-20251001",
    fallbacks: ["claude-sonnet-4-6"],
  },
};

以前の版では、存在するかどうかを確かめないまま claude-haiku-4 のような ID を代役の欄に並べていました。実在しない ID は、フォールバックの途中で必ず失敗します。代役の列こそ、いちばん慎重に書くべき場所でした。

拒否の種類を例外クラスで見分ける

判別の軸は、メッセージの部分一致ではなく、SDK が投げる例外の種類にします。文面は変わっても、ステータスの意味は比較的変わりにくいからです。

import Anthropic from "@anthropic-ai/sdk";
 
type Verdict = "fallback" | "alert" | "rethrow";
 
// 404: モデルが見つからない → 切り替える
// 403: 権限がない → 切り替えず、人に知らせる
// 429 / 529 / その他: SDK の再試行に任せ、フォールバックしない
function classify(err: unknown): Verdict {
  if (err instanceof Anthropic.NotFoundError) return "fallback";
  if (err instanceof Anthropic.PermissionDeniedError) return "alert";
  if (err instanceof Anthropic.BadRequestError) {
    // 400 はパラメータ不備でも返る。モデル起因と読める文面のときだけ切り替える
    const msg = (err.message ?? "").toLowerCase();
    if (msg.includes("unavailable") || msg.includes("not available")) return "fallback";
  }
  return "rethrow";
}
 
async function invokeWithFallback(
  client: Anthropic,
  tier: ModelTier,
  buildRequest: (modelId: string) => Anthropic.Messages.MessageCreateParamsNonStreaming
): Promise<Anthropic.Messages.Message> {
  const chain = FALLBACK_CHAINS[tier];
  const candidates = [chain.primary, ...chain.fallbacks];
  let lastError: unknown;
 
  for (const modelId of candidates) {
    try {
      return await client.messages.create(buildRequest(modelId));
    } catch (err) {
      const verdict = classify(err);
      if (verdict === "fallback") {
        console.warn(`model ${modelId} rejected, trying next`);
        lastError = err;
        continue;
      }
      if (verdict === "alert") {
        await notifyOwner(`permission denied for ${modelId}`); // 通知先は各自の環境で
      }
      throw err; // 切り替え対象でないものは、握りつぶさずに上へ返す
    }
  }
  throw lastError;
}

ここで 429 や 529 を意図的にフォールバックの外に置いているのは、混雑中に代役へ同じ負荷を移しても状況が良くならないからです。再試行は SDK の max_retries に任せ、切り替えは「モデルそのものが受け付けられない」ときだけにします。

モデルごとに違う機能を、表で持つ

もうひとつ、フォールバックで踏みやすいのが機能の食い違いです。優先モデルでは通っていた拡張思考などのパラメータが、代役では受け付けられないことがあります。この場合に返るのは「モデルが使えない」ではなく、パラメータ不備の 400 です。

そこで、モデルごとに「使える機能」を表にして、リクエストを組み立てる側で出し分けます。

interface ModelCapabilities {
  extendedThinking: boolean;
}
 
// 値は例です。対応状況は公式ドキュメントで確かめ、実際の値に書き換えてください
const CAPABILITY_MATRIX: Record<string, ModelCapabilities> = {
  "claude-opus-4-6": { extendedThinking: true },
  "claude-sonnet-4-6": { extendedThinking: true },
  "claude-sonnet-4-5": { extendedThinking: true },
  "claude-haiku-4-5-20251001": { extendedThinking: false },
};
 
function buildRequestForModel(
  modelId: string,
  prompt: string,
  tools: Anthropic.Messages.Tool[]
): Anthropic.Messages.MessageCreateParamsNonStreaming {
  const caps = CAPABILITY_MATRIX[modelId] ?? { extendedThinking: false };
  return {
    model: modelId,
    // 拡張思考を使うときは budget_tokens より大きい max_tokens が必要
    max_tokens: caps.extendedThinking ? 20000 : 4096,
    messages: [{ role: "user", content: prompt }],
    tools,
    ...(caps.extendedThinking
      ? { thinking: { type: "enabled" as const, budget_tokens: 16384 } }
      : {}),
  };
}

以前の私のコードは、max_tokens: 4096 のまま budget_tokens: 16384 を渡していました。拡張思考の予算は max_tokens より小さくなければならないので、これはフォールバック以前に、最初の呼び出しから失敗する書き方です。手元の確認では通っていた「つもり」だったのは、思考を切った経路だけを試していたからでした。

表に載っていない ID には、機能を足さない既定値を当てています。分からないときは、機能を減らして確実に返すほうへ倒す、という線引きです。

切り替わった事実を記録する

フォールバックは、うまく動くほど気づきにくくなります。優先モデルが落ちたまま代役で動き続けていても、画面上は成功に見えるからです。

interface ModelInvocationLog {
  timestamp: string;
  intendedModel: string;
  actualModel: string;
  fallbackDepth: number; // 0 = 優先モデルで成功
  taskType: string;
  outcome: "success" | "all_failed";
}

このログを週に一度だけ集計し、fallbackDepth が 1 以上の割合を眺めます。見直しの目安になる割合は、扱う処理の重要度で変わるので、最初の数週間の実測を見てから自分で決めるのが無理のない進め方です。私も数字を先に決めず、まず記録を貯めるところから始めました。

開発中にこの経路を再現する

本番でしか出ないエラーは、テストが後回しになりがちです。存在しない ID(たとえば claude-opus-99-test)を model に渡すと、モデルが見つからない旨の 404 が返ってくるはずです。実際に返った応答を一度ログに残し、classify の単体テストのデータに使うと、フォールバックの全段が正しく次へ進むかを CI で確かめられます。

本番でモデルが落ちた瞬間に「ここは試していなかった」と気づくのは、胃が痛くなる経験でした。その夜から、チェーンの全段が失敗した場合の動き(throw lastError に至る経路)も、テストに含めるようにしています。

まず一つだけ、今日やること

次の一行を、いまのコードに足してみてください。優先モデルで呼び出したあとに、実際に使われたモデル ID を、レスポンスの model フィールドからログへ残す、というだけです。フォールバックを作る前に、どのくらい切り替わっているのかが見えるようになります。

そのうえで、404 と 403 を切り分ける classify を入れていただければ、権限の問題を代役で隠してしまう失敗は避けられます。

シェア

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

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

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

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

関連記事

⬡ API & SDK2026-05-22
Claude API の tool_result could not be submitted が再発しないための回復ハンドラ設計
Claude API でエージェントを長時間動かしていると、ある日突然 'tool_result could not be submitted' が連発し始めることがあります。再試行しても直らない、ストリーミング途中で死ぬ、そして次のセッションでもまた出る — 常時稼働のエージェント基盤で実際に踏み抜いた4種類の原因と、TypeScript で書いた回復ハンドラの実装を整理しました。
⬡ API & SDK2026-05-09
Claude API の 400/422/529 を“呼ぶ前”に消す5層プリフライト設計 — 月数百件の失敗呼び出しをゼロにした実装
Claude API の 400/422/529 エラーを“呼ぶ前”に止める5層プリフライト設計を、TypeScript の完全実装と運用1ヶ月分の数値でまとめました。失敗呼び出しのコスト・リトライ・通知ノイズを同時に削減できます。
⬡ API & SDK2026-04-23
Claude API の高可用性設計 — Sonnet / Haiku / Opus マルチモデルフォールバックを本番で成立させる
Claude API を単一モデル前提で組むと、障害やレート制限の瞬間にサービス全体が止まります。Sonnet・Haiku・Opus を段階的にフォールバックする本番実装を、コード・Circuit Breaker・ストリーミング対応まで含めて整理しました。