Claude Codeデバッグワークフロー: 観察、再現、修正、テスト
TypeScript、Node、VitestでClaude Codeのデバッグを調査、再現、修正、回帰テストまで進める実践ガイドです。
Claude Codeはエラーを貼るだけでも修正案を出せます。しかし実務のデバッグで大事なのは、早く直すことだけではありません。原因を観察し、再現条件を固定し、最小の修正を行い、同じバグが戻らないテストを残すことです。ここを省くと、見た目は直ったのに別の画面や別の言語ページで壊れることがあります。
この記事では、観察、仮説、最小再現、修正、回帰テストの順でClaude Codeを使います。関連するテスト設計は Claude CodeとTDD、例外処理の考え方は error handling patterns、build失敗の切り分けは build error triage loop と合わせて読むと実務で使いやすくなります。
曖昧な修正依頼ではなく調査手順を渡す
「このエラーを直して」だけでは、Claude Codeは最短の修正に寄りがちです。最短の修正が悪いわけではありませんが、原因を証明しないまま入れた修正は、次の変更で戻る可能性があります。まずはエラーメッセージ、stack trace、入力データ、再現手順、期待する結果、直近の変更を並べます。
この順番にすると、Claude Codeは事実と推測を分けやすくなります。たとえばAPIレスポンスが undefined なのか、空配列なのか、配列だがnameが空なのかで修正は違います。デバッグでは、実装前に「どの条件をバグとして扱うか」を決めることが重要です。
{
"name": "claude-debug-lab",
"private": true,
"type": "module",
"scripts": {
"test": "vitest run",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@types/node": "^22.0.0",
"typescript": "^5.6.0",
"vitest": "^3.0.0"
}
}
例1: undefinedのmapエラーを仕様に落とす
最初の例は、APIのpayloadが欠けたときに配列処理が落ちるケースです。ここでの目的は、クラッシュを消すだけではありません。欠けたpayloadは空リストとして扱い、空の表示名は除外する、という仕様をテストに残します。
export type User = {
id: string;
name?: string | null;
};
export function normalizeUsers(users: User[] | null | undefined): string[] {
if (!Array.isArray(users)) return [];
return users
.filter((user): user is User & { name: string } => typeof user.name === "string")
.map((user) => user.name.trim())
.filter((name) => name.length > 0);
}
import { describe, expect, it } from "vitest";
import { normalizeUsers } from "../src/normalize-users.js";
describe("normalizeUsers", () => {
it("returns an empty list when the API payload is missing", () => {
expect(normalizeUsers(undefined)).toEqual([]);
expect(normalizeUsers(null)).toEqual([]);
});
it("keeps only usable display names", () => {
expect(
normalizeUsers([
{ id: "u1", name: " Masa " },
{ id: "u2", name: "" },
{ id: "u3", name: null },
]),
).toEqual(["Masa"]);
});
});
Claude Codeには次のように頼みます。
Cannot read properties of undefined (reading 'map') が出ています。
normalizeUsers は API payload が欠けても落ちず、空の表示名を除外する必要があります。
先に失敗するVitestを追加し、その後に最小修正を行ってください。
npm test と npm run typecheck の結果も報告してください。
よくある落とし穴は、users ?? [] だけで終えることです。それでクラッシュは消えても、null name、空文字、配列ではないpayloadの扱いが曖昧に残ります。Claude Codeに仕様を渡すと、修正とテストが同じ方向を向きます。
例2: 非同期retryが最後のエラーを隠す
非同期処理のバグは「たまに動く」ように見えます。retry処理では、何回呼ばれたか、待機したか、最後のエラーを投げ直したかを固定します。ログを眺めるだけではなく、成功するretryと全失敗の両方をテストにします。
type RetryOptions = {
times: number;
delayMs: number;
sleep?: (ms: number) => Promise<void>;
};
const defaultSleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
export async function retry<T>(
task: () => Promise<T>,
{ times, delayMs, sleep = defaultSleep }: RetryOptions,
): Promise<T> {
let lastError: unknown;
for (let attempt = 1; attempt <= times; attempt += 1) {
try {
return await task();
} catch (error) {
lastError = error;
if (attempt < times) await sleep(delayMs);
}
}
throw lastError instanceof Error ? lastError : new Error("Retry failed");
}
Claude Codeには、mockの状態がテスト間で漏れないこと、広いリファクタをしないこと、最終エラーを飲み込まないことを明示します。Vitestのmockは便利ですが、共有状態を放置すると成功したり失敗したりする不安定なテストになります。調査用ログを入れた場合は、最後に必ず削除します。
例3: 日付境界を最小再現で固定する
三つ目の実例は、月次CSVや請求書でよく起きる日付境界のバグです。画面では「3月を選んだのに3月31日のデータが消える」と見えますが、原因はUIではなく、月初と翌月月初の比較条件にあることが多いです。こういうバグはスクリーンショットだけを渡すより、入力配列と期待するIDをテストにした方がClaude Codeの調査精度が上がります。
export type Order = {
id: string;
createdAt: string;
total: number;
};
export function exportMonthlyOrderIds(orders: Order[], month: string): string[] {
const [yearText, monthText] = month.split("-");
const year = Number(yearText);
const monthIndex = Number(monthText) - 1;
const start = new Date(Date.UTC(year, monthIndex, 1));
const end = new Date(Date.UTC(year, monthIndex + 1, 1));
return orders
.filter((order) => {
const createdAt = new Date(order.createdAt);
return createdAt >= start && createdAt < end;
})
.map((order) => order.id);
}
import { describe, expect, it } from "vitest";
import { exportMonthlyOrderIds } from "../src/export-orders.js";
describe("exportMonthlyOrderIds", () => {
it("includes orders from the first day through the last moment of the month in UTC", () => {
const orders = [
{ id: "feb-end", createdAt: "2026-02-28T23:59:59.999Z", total: 1000 },
{ id: "mar-start", createdAt: "2026-03-01T00:00:00.000Z", total: 2000 },
{ id: "mar-end", createdAt: "2026-03-31T23:59:59.999Z", total: 3000 },
{ id: "apr-start", createdAt: "2026-04-01T00:00:00.000Z", total: 4000 },
];
expect(exportMonthlyOrderIds(orders, "2026-03")).toEqual(["mar-start", "mar-end"]);
});
});
Claude Codeには「ローカルタイムゾーンに依存しない」「開始日は含める」「翌月開始は含めない」と条件を明記します。new Date("2026-03") のような曖昧なパースは、環境差でCIと本番の結果がずれることがあります。日付のデバッグでは、画面操作の説明だけでなく、境界値のテストを先に作らせるのが安全です。
初心者が詰まりやすいのは、バグの場所を最初から当てようとすることです。実務では、最初の推測が外れることは普通にあります。だからこそClaude Codeには「まず観測を整理して」「次に仮説を3つ出して」「最後に一番小さい再現コードへ落として」と分けて頼みます。デバッグの目的は一発で当てることではなく、外れた仮説を安く捨てて、正しい原因に近づくことです。
デバッグ用プロンプトテンプレート
目的:
原因を特定し、回帰テストを追加し、最小修正で直してください。
観察:
- エラー全文:
- 再現手順:
- 期待結果:
- 実際の結果:
- 直近で変更したファイル:
制約:
- 先に仮説を3つ出す
- 大きなリファクタをしない
- anyで型エラーを隠さない
- 追加したログは最後に削除する
- npm test と npm run typecheck を最後に実行する
報告:
- 原因
- 変更ファイル
- 追加した回帰テスト
- 残るリスク
このテンプレートを使うと、Claude Codeは単なる修正係ではなく調査相手になります。レビュー担当者も、差分を読む前に原因、証拠、残リスクを把握できます。チームで使う場合は review gate に同じ項目を入れると、AIが作った差分も人間の差分も同じ基準で見られます。
収益導線を壊さないデバッグ
公開サイトのデバッグでは、機能だけでなくCTAも確認します。記事の本文を直した結果、無料PDFフォームが下へ押し出される、Gumroadリンクが別商品へ変わる、導入相談フォームに戻れない、という問題が起きることがあります。PVが高い記事ほど、デバッグの影響範囲に収益導線を入れるべきです。
CTAの分岐は次のように固定できます。
const debuggingRoutes = {
first_error: "free_pdf",
repeated_bugfixes: "prompt_templates",
setup_or_ci_blocked: "setup_guide",
team_process_blocked: "consultation",
};
export function chooseDebuggingCta(intent) {
return debuggingRoutes[intent] ?? "free_pdf";
}
console.log(chooseDebuggingCta("repeated_bugfixes"));
初心者には free cheatsheet、繰り返しのdebuggingやreviewには 50 Prompt Templates、権限やCI/CDが詰まる場合は Setup Guide、チーム導入や運用設計は 導入相談 が合います。
この記事で確認したこと
この記事は、正常なUTF-8本文、5つ以上の見出し、実行可能なコードブロック、内部リンク、外部リンク、無料PDF、Gumroad、導入相談の導線を含みます。次に見る数字は、このデバッグ記事からPDF登録、Prompt Templatesクリック、Setup Guideクリック、Trainingページ到達へ進む率です。
公開後のデバッグ確認メモ
デバッグ記事を公開するときは、コードの正しさだけで完了にしません。公開URLでh1、canonical、本文冒頭、hero image、無料PDFフォーム、Gumroadリンク、導入相談リンクを確認します。とくに人気記事では、デバッグ手順の改善が読者の次の行動に直結します。本文が読みやすくなっても、PDF登録ができない、Gumroad商品が違う、相談フォームに進めないなら、収益導線としては未完成です。
多言語版では、コード例は共通でも本文の説明とCTAは対象言語である必要があります。日本語版なら日本語で、中文なら中文で、韓国語版なら韓国語で、読者がどの順番で試すべきかを説明します。見出しだけ翻訳されて本文が英語のまま残ると、初心者は作業を止めます。スクリーンショット確認では、本文冒頭、promptテンプレート付近、CTA付近を必ず見るべきです。
次に見る数字は、この記事からの無料PDF登録、Prompt Templatesクリック、Setup Guideクリック、Trainingページ到達です。debugging読者は問題意識が強いため、単なるPVよりも、どの導線に進んだかの方が価値があります。Claude Codeに次の改善を頼むときは、この数字を最初に渡し、本文の補足、CTAの優先順位、Productsページのカード、相談フォームの説明を同じ方向にそろえます。
デバッグ記事は、読者が実際に手元で試す可能性が高い記事です。そのため、コード例の構文、promptの順番、失敗例の具体性、最後に見るべき指標をそろえておく必要があります。記事を読んだ人が「何を貼ればよいか」「どのテストを先に作るか」「いつ有料教材や相談に進むか」を判断できれば、記事は単なる情報ではなく作業の入口になります。
数字が伸びない場合は、本文の長さよりも摩擦を見ます。無料PDFフォームが遠すぎないか、Prompt Templatesへの説明がdebugging読者の悩みに合っているか、Setup Guideや導入相談がチーム導入の文脈で紹介されているかを確認します。デバッグ記事は問題意識の強い読者が読むため、CTAの文脈が合えば小さな改善でも登録や購入につながりやすくなります。
最後に、修正した記事は公開URLで必ず読みます。ローカルbuildで通っても、公開環境で違うslug、古い本文、トップページfallbackが表示されることがあります。h1、本文冒頭、コード例、CTA、canonicalを同じ画面で確認してから、次の改善に進みます。
この確認を省くと、読者には直った記事ではなく壊れた導線が届きます。デバッグ記事ほど、修正結果と公開結果を分けて考える必要があります。最後の確認ログが残っていれば、翌日の改善では同じバグを疑うより、読者の次の行動を改善する判断に進めます。修正、公開、計測をつなぐことが毎日の運用です。日本語の読者には、最初に貼るエラー、作るテスト、最後に見るCTAを明確に示すほど、記事から行動へ移りやすくなります。これも公開後の重要な検証項目です。必ず毎回記録します。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
ObsidianメモをCLAUDE.mdに変えるClaude Code運用: 文脈を毎回説明しない仕組み
Obsidianの作業メモからCLAUDE.md用の運用ノートを作り、Claude Codeに安定した文脈を渡す方法。
Claude Code Revenue CTA Routing: 記事からPDF、Gumroad、相談へ送る設計
PVだけで終わらせず、読者の状態に合わせて無料PDF、Gumroad教材、導入相談へ分岐するCTA設計です。
Claude Codeチーム引き継ぎルール: レビュー、権限、収益導線まで渡す実務手順
Claude Codeの作業をチームで渡すための証拠、権限、ロールバック、無料PDF/Gumroad/相談導線の実務ルール。