バグ報告テンプレートの書き方: 「直して」が伝わるissueの型をコピペで
「画面が壊れてる」が伝わらないのは情報不足が原因。タイトル・再現手順・期待と実際・環境・ログの並べ方を、コピペで使えるissueテンプレと自動生成スクリプトで整えます。
「画面が壊れてます」
僕が新人のころ、先輩にそう報告したら、無言で席まで来られました。どの画面?どの操作?何が「壊れて」るの?——質問攻めにあって、結局その場で全部聞かれ直したんです。報告した意味、ほぼゼロでした。
これ、相手がClaude Codeでも同じです。「テストが落ちます、直して」とだけ渡すと、いちばんありそうな原因に飛びついて、それっぽい修正を返してきます。早い。でも外す。そして同じバグが別の形でまた出る。
理由はシンプルで、バグ報告は「気持ち」じゃなくて「型」だからです。料理の注文と同じで、「いい感じのやつ」では出てこない。何を、どう、どこまで、を埋めた一枚があれば、人間にもAIにも同じように伝わります。今日はその型——コピペで使えるバグ報告テンプレートの作り方を、僕の失敗込みで書きます。調査そのものの進め方は姉妹記事の最初の不具合報告Runbookに分けたので、ここでは「報告の書式」に集中します。
この記事の要点
- バグ報告は文章力じゃなく項目の埋め方。タイトル・再現手順・期待・実際・環境・証拠・影響範囲の7点を固定する。
- タイトルは「何が・どこで・どうなる」を一行で。「不具合」だけのタイトルは検索でも一覧でも埋もれる。
- 期待結果と実際の結果を必ず分ける。ここが抜けると「直った」の判定ができない。
- 環境とログは全部貼らない。再現に効く差分と、エラー周辺の数十行だけに絞る。秘密情報は型から弾く。
- 下のテンプレを
bug-report.mdに保存し、環境情報はcollect-bug-context.mjsで自動収集する。手で集めると必ず抜ける。
なぜ「型」がないと伝わらないのか
バグ報告がうまくいかないとき、原因はたいてい「書いた人の頭の中にしか情報がない」状態です。
書いた本人は、どの画面でどう操作したか、いつから変か、全部知っています。だから「壊れてます」で通じる気がする。でも読む側——レビュー担当者でもClaude Codeでも——は、その前提をひとつも共有していません。ここに大きなズレが生まれます。
型の役割は、この「頭の中」を強制的に外に出させることです。空欄が並んでいると、人は埋めようとします。「期待結果:」という欄があれば、「あ、本来どうなるべきか書いてなかった」と気づく。チェックリストが思考の抜けを拾ってくれるわけです。
しかも型には副作用があります。書いている途中で自己解決することがある。再現手順を1, 2, 3と書き出すうちに「あれ、手順2を飛ばすと再現しないぞ」と当たりがつく。デバッグの半分は、現象を言語化した瞬間に終わっていたりします。
バグ報告に必ず入れる7項目
長文である必要はありません。むしろ短いほうがいい。ただし、次の7つは省かないでください。
| 項目 | 何を書くか | これで判断できること |
|---|---|---|
| タイトル | 何が・どこで・どうなるかを一行で | 一覧での識別、優先度づけ |
| 再現手順 | 3分で再現できる最小ステップ | 原因候補の検証方法 |
| 期待結果 | 本来どう動くべきか | 「直った」の合格条件 |
| 実際の結果 | エラー文、HTTPステータス、崩れ方 | 事実と推測の切り分け |
| 環境 | OS、Node、ブラウザ、ブランチ、設定 | ローカル固有か共通かの判定 |
| 証拠 | ログ、スクショ、失敗テスト | 修正前後の比較 |
| 影響範囲 | 誰が困るか、触ってよい範囲 | 優先度と修正の広さ |
初心者がいちばん落とすのは「期待結果」です。「エラーを消す」だけだと、空配列を返すのか、400を返すのか、画面に警告を出すのが正解なのか、誰にも分かりません。期待結果は仕様書みたいに完璧じゃなくていい。「モバイル幅でCTAが縦に並び、横スクロールが出ない」みたいに、目で確認できる一文にするのがコツです。
タイトルだけで9割決まる
バグ報告で、僕がいちばん時間を割くのがタイトルです。地味ですが、ここが全部を引っ張ります。
ダメなタイトルの典型はこれ。
・不具合
・バグです
・スマホで変
・テストが落ちる
どれも「何が・どこで・どうなる」が入っていません。一覧に10件並んだら、どれを先に見ればいいか分からない。一方、効くタイトルはこうです。
・[products] 390px幅で価格CTAが画面外にはみ出して横スクロールが出る
・[checkout API] plan=pro のときだけ POST が500を返す
・[月次集計] 3月31日23:59(UTC)の注文がCSVに含まれない
公式の型は「[場所] 条件のときに、何がどうなる」。角括弧で場所(画面・API・モジュール)を頭に出すと、一覧でグルーピングできて優先度づけが一瞬で済みます。そして「条件」を入れるのが効く。「500を返す」より「plan=proのときだけ500を返す」のほうが、読んだ瞬間に原因の見当がつくからです。
タイトルが具体的に書けないときは、たいてい現象をまだ理解できていません。その場合は無理にタイトルを盛らず、再現手順から先に埋めます。書いているうちに、タイトルに入れるべき「条件」が見えてきます。
再現手順は「最小」が正義
再現手順でやりがちなのが、本番と同じ状況を全部書こうとすることです。「ログインして、ダッシュボード開いて、設定行って、プロフィール編集して…」みたいに。
逆です。バグを起こすのに必要な手順だけを残します。要らない操作を削るほど、原因の範囲が狭まる。これは姉妹記事の最初の不具合報告Runbookで詳しく掘っていますが、報告の書式としては最低限こうします。
- どこで(URL、コマンド、エンドポイント)
- どう操作したか(クリック、入力値、リクエスト)
- 何が起きたか(画面、ステータス、ログ)
例えばAPIのバグなら、画面操作を全部すっ飛ばしてcurl一発に落とすのが最強です。
curl -X POST http://localhost:3000/api/checkout \
-H "content-type: application/json" \
-d '{"plan":"pro"}'
これがそのまま再現手順になり、あとで失敗テストの土台にもなります。「手順を最小化できない=まだ現象を絞れていない」のサインだと思ってください。
コピペで使えるバグ報告テンプレート
ここが本題です。次のテンプレートをbug-report.mdとして保存し、空欄を埋めてから使ってください。社内のissue、GitHubのバグ報告、Claude Codeへの依頼、どれにもそのまま貼れます。
# バグ報告
## タイトル
[場所] 条件のときに、何がどうなるか(一行)
## 影響範囲
- 誰が困るか:
- 発生頻度: 毎回 / ときどき / 不明
- 優先度: 高 / 中 / 低
## 環境
- OS:
- Node / パッケージマネージャ:
- ブラウザ / デバイス:
- ブランチ:
- 関連するenv名(値は書かない):
## 再現手順(最小)
1.
2.
3.
## 期待結果
-
## 実際の結果
- エラーメッセージ:
- HTTPステータス / 崩れ方:
## 証拠
- ログ(エラー周辺だけ):
- スクリーンショット:
- 失敗しているコマンド / テスト:
## 最近の変更
- 関連しそうなPR / commit:
- 変わった可能性が高いファイル:
## 制約(任意・依頼相手がいる場合)
- 触ってよい範囲:
- 触らない範囲:
- 秘密情報・顧客データは貼らない:
ポイントは、項目の順番です。タイトルと影響範囲を先頭に置くと、読む人が「自分が今すぐ見るべきか」を最初の5秒で判断できます。技術詳細(環境・証拠)は後ろでいい。優先度の高い人ほど、上から数行しか読まないからです。
このテンプレを使うとき、僕は「期待結果」と「実際の結果」だけは絶対に空欄で出しません。この2つが揃っていれば、最悪ほかが薄くても会話が始まります。逆にこの2つがないと、まず「で、どうなってほしいの?」から聞き直しになります。
環境情報は手で集めない(自動収集スクリプト)
環境欄、手で埋めると必ずどこか抜けます。ブランチ名を書き忘れる、Nodeのバージョンが実は古かった、直近のコミットを見落とす。僕は何度もやりました。
なので環境情報は機械に集めさせます。次のスクリプトはNode.jsだけで動いて、秘密情報っぽい値をマスクしながら、報告に貼る文脈をまとめてくれます。元の記事から引き続き使えるものです。
// scripts/collect-bug-context.mjs
import { execFileSync } from "node:child_process";
import { existsSync, readFileSync } from "node:fs";
import { platform, release } from "node:os";
import { cwd } from "node:process";
// gitコマンド等を安全に実行(失敗しても落とさず印を残す)
function run(command, args) {
try {
return execFileSync(command, args, {
cwd: cwd(),
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
}).trim();
} catch (error) {
return `(failed: ${command} ${args.join(" ")})`;
}
}
// APIキーやトークンらしき文字列を伏せる(保険)
function maskSecrets(text) {
return text
.replace(/(api[_-]?key|token|secret|password)=([^\s]+)/gi, "$1=***")
.replace(/Bearer\s+[A-Za-z0-9._-]+/g, "Bearer ***");
}
// package.jsonのscriptsだけ抜き出す(どの検証コマンドがあるか)
function readPackageScripts() {
if (!existsSync("package.json")) return "package.json not found";
const pkg = JSON.parse(readFileSync("package.json", "utf8"));
return JSON.stringify(pkg.scripts ?? {}, null, 2);
}
const report = {
generatedAt: new Date().toISOString(),
cwd: cwd(),
os: `${platform()} ${release()}`,
node: process.version,
branch: run("git", ["branch", "--show-current"]),
status: run("git", ["status", "--short"]),
lastCommit: run("git", ["log", "-1", "--oneline"]),
diffStat: run("git", ["diff", "--stat"]),
packageScripts: readPackageScripts(),
};
console.log(maskSecrets(JSON.stringify(report, null, 2)));
使い方はこれだけ。
mkdir -p scripts
# 上のコードを scripts/collect-bug-context.mjs に保存
node scripts/collect-bug-context.mjs > bug-context.json
出力されたbug-context.jsonを報告の「環境」欄に貼れば、ブランチ・差分・実行できる検証コマンドが一発でそろいます。ただしマスク処理はあくまで保険です。APIキー、顧客データ、本番ログの全文は貼らない。必要な行だけに絞ってください。
証拠とログの添え方
証拠は「多ければ多いほどいい」ではありません。安全に共有できるものを、必要なぶんだけが正解です。
スクリーンショットは、崩れている箇所が分かるように撮ります。画面全体より、はみ出している要素+ブラウザの幅表示が入っているほうが効く。DevToolsでdocument.documentElement.scrollWidthが412になっている、みたいな数値が一つあると、文章より強い証拠になります。
ログは全文を貼らないでください。理由は二つ。長すぎるとAIのコンテキストを圧迫して肝心な行が埋もれること、そして全文ログには秘密情報が混ざりやすいことです。貼るのは「エラーが出た行の前後20行」「リクエストID」「再現コマンド」くらいに絞ります。
日付・タイムゾーン・金額みたいな純粋なロジックのバグは、スクショより失敗するテストが最強の証拠です。例えばこんな形。
import { describe, expect, it } from "vitest";
import { exportMonthlyOrderIds } from "../src/export-orders";
describe("exportMonthlyOrderIds", () => {
it("3月の注文を含み、4月1日0時(UTC)を含まない", () => {
const orders = [
{ id: "mar-start", createdAt: "2026-03-01T00:00:00.000Z" },
{ id: "mar-end", createdAt: "2026-03-31T23:59:59.999Z" },
{ id: "apr-start", createdAt: "2026-04-01T00:00:00.000Z" },
];
expect(exportMonthlyOrderIds(orders, "2026-03")).toEqual(["mar-start", "mar-end"]);
});
});
このテストを報告に添えて「まずこれを失敗させてから、ローカルのタイムゾーンに依存しない実装に直して」と頼むと、修正後も同じバグが戻りにくくなります。文章で「月末がおかしい」と書くより、落ちるテスト一個のほうが100倍伝わります。どのバグをテスト化すべきか迷ったら、テスト戦略の優先順位で境界値・データ変換・API契約あたりから守る、という線引きを決めておくとラクです。
Claude Codeに渡すときの一手
人間に渡すならテンプレを埋めるだけで十分です。相手がClaude Codeなら、もう一手だけ足します。「すぐ直さないで」と先に言うことです。
埋めたbug-report.mdとbug-context.jsonを渡して、次のプロンプトを添えます。
このbug-report.mdとbug-context.jsonを読んでください。
進め方:
1. まだ編集しない
2. 事実と推測を分ける
3. 原因候補を可能性順に3つ挙げる
4. 各候補を否定できる最小の確認手順を出す
5. 最小再現か失敗テストを先に作る
6. 承認後に最小差分で直す
完了条件:
- 期待結果と実際の結果の差が説明されている
- 失敗テストか再現コマンドが残っている
- 実行した検証コマンドが報告されている
- PRに貼れる根本原因・修正内容・残リスクがある
公式のよくあるワークフローでも、バグ修正のコツとして「再現コマンドを伝える」「再現手順を添える」「断続的か一貫して起きるかを言う」が挙げられています。テンプレの項目とそのまま噛み合います。
一つ注意。自分のアプリのバグ報告と、Claude Code本体の不具合報告は混ぜないこと。セッション付きでClaude Codeチームにフィードバックを送るのは/feedback(別名 /bug)、自分の環境の調子を見るのは/doctorや/debugです。テンプレで扱うのはあくまで「自分のコードのバグ」です。
やりがちな失敗5つ(全部やった)
正直に書きます。僕が踏んだ地雷です。
ひとつ目、1つの報告に複数のバグを詰める。ログインも決済もレイアウトも一気に、とやると、相手は広い範囲をいじって差分が膨らみます。1報告1症状に分けるだけで、解決が速くなります。
ふたつ目、ログを貼りすぎる。全文を貼ると親切なつもりが、肝心のエラー行が埋もれ、秘密情報のリスクも上がる。エラー周辺と再現コマンドに絞ります。
みっつ目、期待結果を書かない。これがいちばん多い。「直して」だけだと合格ラインが共有されず、見当違いの修正でも「動いてるじゃん」で通ってしまいます。
よっつ目、「全部見て直して」と丸投げする。範囲を広げると安心する気持ちは分かります。でも実務は逆で、最小再現に絞るほど直りが速い。
いつつ目、影響範囲を書かない。誰が困るバグなのかが無いと、優先度がつけられません。「全ユーザーの決済が止まる」と「一部の表示が崩れる」では、扱いがまるで違います。
修正できたら、根本原因・直した内容・残リスクをPR本文に残します。ここはセッション引き継ぎテンプレートと同じ発想で、次に読む人の調査時間を削るためです。バグ報告とPR引き継ぎは、入口と出口の関係になっています。
よくある質問
Q. バグ報告はどれくらい詳しく書けばいい? A. 長さではなく7項目が埋まっているかで判断します。特に「期待結果」「実際の結果」「最小再現」の3つが揃っていれば、短くても会話が始まります。
Q. 再現手順が安定しない(たまにしか起きない)ときは? A. 「ときどき」と正直に書いた上で、時計・乱数・キャッシュ・リトライ・並列実行のどれかを疑う、と添えます。不安定さを隠す修正(待ち時間を増やすだけ等)を防げます。
Q. ログはどこまで貼っていい? A. エラー周辺の20行前後、リクエストID、再現コマンドまで。全文ログとAPIキー・顧客データは貼りません。値ではなく「どのenv名を使っているか」を書きます。
Q. GitHubのissueテンプレートとして使える?
A. そのまま使えます。.github/ISSUE_TEMPLATE/bug_report.mdに置けば、新規issueで自動的にこの型が出ます。チームで書式を揃えると、報告の質が一気に安定します。
Q. Claude Codeに直接バグを直してもらうのと何が違う? A. テンプレは「相手が人でもAIでも通じる事実」を残すのが目的です。Claude Codeに渡すなら「すぐ直さず原因候補を3つ」と先に縛ると、外れた仮説を早く捨てられて、調査の質が上がります。手順の詳細は最初の不具合報告Runbookへ。
実際に試した結果
このテンプレを使い始めてから、僕がレビューで聞き返す回数が目に見えて減りました。
いちばん効いたのは、やっぱりタイトルと「期待結果・実際の結果」です。タイトルに「条件」を入れる癖がつくと、書いている本人が現象を理解しているかどうかが一目で分かる。理解できていない報告は、タイトルがふわっとするんですね。そういう報告は、再現手順から埋め直してもらうようにしました。
Claude Codeに渡すときは、テンプレ+「すぐ直さず原因候補3つ」の組み合わせが安定しました。最初に仮説を3つ出させると、外れたものを早めに捨てられて、修正そのものより前の調査がきれいになります。差分も小さくなり、レビューがコードの良し悪しに集中できるようになりました。
まずは今の自分のリポジトリで、bug-report.mdとcollect-bug-context.mjsを置くところから始めてみてください。繰り返し使うプロンプトやレビュー観点まで一式そろえたい人は教材一覧を、チームで報告書式・権限・PRレビューを標準化したい人は研修・相談をのぞいてみてください。調査の進め方そのものは、姉妹記事の最初の不具合報告Runbookに続きます。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Codeに1ファイルだけ直させる指示文のつくり方
「もっと良くして」で40行も変えられた失敗から学んだ、触る範囲・検証・戻し方をセットにしたClaude Code用の依頼文テンプレートを紹介します。
Claude Code の権限拒否から復旧する: 止まった理由を次の安全手順に変える
Claude Code のコマンドが拒否されたとき、焦って許可を広げずに、拒否理由、代替手順、証拠コマンド、再試行条件へ分解する方法。
Claude Codeにビルド→スモークテスト→自動修正を回させる足場の作り方
最小スモークテストの選び方、失敗ログを食わせて直させるループ、回数上限と確認ゲートで暴走を止める方法を、コピペで動くコード付きで紹介します。