エラーコード定義の位置づけ
エラーコードは「システムの言語」だ。エラーが発生したとき、ユーザー・サポート担当・開発者が同じコードを使って話せることが重要だ。設計段階でコード体系・メッセージの粒度を決めておかないと、実装が進むにつれてコードが乱立する。
💡 2種類のメッセージを分離する
エラーメッセージは「ユーザー向け」と「ログ向け」の2種類を必ず分離して定義する。ユーザー向けは「入力内容を確認してください」のような案内文、ログ向けは「order_id=12345 の在庫引当で NullPointerException 発生」のような技術詳細だ。
コード体系設計
■ エラーコード形式: [カテゴリ]_[番号]
カテゴリ一覧:
AUTH — 認証・認可エラー (AUTH_001〜AUTH_099)
VAL — バリデーションエラー (VAL_001〜VAL_199)
BIZ — 業務ロジックエラー (BIZ_001〜BIZ_299)
DB — データベースエラー (DB_001〜DB_099)
IF — 外部IFエラー (IF_001〜IF_099)
SYS — システム内部エラー (SYS_001〜SYS_099)
■ HTTP ステータスとの対応方針
AUTH_* → 401 or 403
VAL_* → 400
BIZ_* → 400 or 409(業務的に処理できない場合)
DB_* → 500(ユーザーにDBエラーは見せない)
IF_* → 503(外部IF障害時)
SYS_* → 500
■ 番号採番ルール
3桁 001〜099: 汎用エラー(全機能共通)
100〜199: 機能別エラー(機能IDと対応)
例: VAL_101 = 機能01のバリデーションエラー第1号
定義すべき項目一覧
| 項目 | 説明 | 必須度 |
|---|---|---|
| エラーコード | 一意のコード(AUTH_001 等) | ◎ |
| HTTPステータス | 対応するHTTPステータスコード | ◎ |
| ユーザー向けメッセージ | エンドユーザーに表示する文章 | ◎ |
| ログ向けメッセージ | ログに出力する技術詳細メッセージ | ◎ |
| 発生条件 | このエラーが発生する具体的な条件 | ◎ |
| 対応方針 | リトライ可否・対応手順 | ○ |
| 多言語メッセージ | 英語など多言語対応が必要な場合 | △ |
ユーザー向けメッセージ
| エラーコード | ユーザー向けメッセージ(日本語) | NGな例 |
|---|---|---|
| AUTH_001 | ログインしてください。セッションが切れた可能性があります。 | 401 Unauthorized |
| VAL_001 | 入力内容に誤りがあります。赤枠の項目を確認してください。 | バリデーションエラーです |
| BIZ_001 | 在庫が不足しています。数量を変更するか、後日改めてお試しください。 | 在庫引当エラー: stock=-3 |
| SYS_001 | システムエラーが発生しました。しばらく経ってから再度お試しください。 | NullPointerException at OrderService.java:152 |
ログ向けメッセージ
■ ログ出力フォーマット
{timestamp} {level} [{traceId}] {errorCode} {logMessage} {context}
■ ログ向けメッセージテンプレート(プレースホルダー付き)
BIZ_001: "在庫引当失敗 product_id={product_id} requested={qty} available={available}"
→ 出力例: 2026-06-18T12:00:00Z ERROR [abc123] BIZ_001 在庫引当失敗 product_id=456 requested=10 available=3
DB_001: "DB接続エラー host={host} db={db} elapsed_ms={elapsed}"
→ 出力例: 2026-06-18T12:01:00Z ERROR [def456] DB_001 DB接続エラー host=db01 db=myapp elapsed_ms=5001
IF_001: "外部IF応答エラー if_id={if_id} status={status} elapsed_ms={elapsed} response={body_excerpt}"
→ 出力例: 2026-06-18T12:02:00Z ERROR [ghi789] IF_001 外部IF応答エラー if_id=IF-001 status=500 elapsed_ms=3210
■ 必ず含める情報
- トレースID(リクエスト単位の一意ID)
- エラーコード
- コンテキスト情報(IDや値)
- 個人情報・パスワードはログに出力しない
多言語対応
// messages.ja.json
{
"AUTH_001": "ログインしてください。セッションが切れた可能性があります。",
"VAL_001": "入力内容に誤りがあります。赤枠の項目を確認してください。",
"BIZ_001": "在庫が不足しています。数量を変更するか、後日改めてお試しください。",
"SYS_001": "システムエラーが発生しました。しばらく経ってから再度お試しください。"
}
// messages.en.json
{
"AUTH_001": "Please log in. Your session may have expired.",
"VAL_001": "There are errors in your input. Please check the highlighted fields.",
"BIZ_001": "Insufficient stock. Please change the quantity or try again later.",
"SYS_001": "A system error occurred. Please try again after a while."
}
Python Tips — エラーコード定義ファイルの自動生成
"""
エラーコード定義(単一 CSV)から JSON / Java Enum / Python Enum を自動生成する
"""
import csv, json
# エラーコード定義ファイル(マスタ)
DEFINITIONS = [
{"code":"AUTH_001","http":401,"user_msg_ja":"ログインしてください。","user_msg_en":"Please log in.","log_msg":"認証トークンなし","category":"AUTH"},
{"code":"VAL_001", "http":400,"user_msg_ja":"入力内容に誤りがあります。","user_msg_en":"Input error.","log_msg":"必須項目が空白 field={field}","category":"VAL"},
{"code":"BIZ_001", "http":400,"user_msg_ja":"在庫が不足しています。","user_msg_en":"Insufficient stock.","log_msg":"在庫引当失敗 product_id={product_id}","category":"BIZ"},
{"code":"SYS_001", "http":500,"user_msg_ja":"システムエラーです。","user_msg_en":"System error.","log_msg":"予期しない例外 {exception}","category":"SYS"},
]
# 1. 日本語メッセージ JSON
ja_msgs = {d["code"]: d["user_msg_ja"] for d in DEFINITIONS}
with open("messages.ja.json", "w", encoding="utf-8") as f:
json.dump(ja_msgs, f, ensure_ascii=False, indent=2)
# 2. 英語メッセージ JSON
en_msgs = {d["code"]: d["user_msg_en"] for d in DEFINITIONS}
with open("messages.en.json", "w", encoding="utf-8") as f:
json.dump(en_msgs, f, ensure_ascii=False, indent=2)
# 3. Python Enum
lines = ["from enum import Enum", "", "class ErrorCode(Enum):"]
for d in DEFINITIONS:
name = d["code"].replace("-", "_")
lines.append(f' {name} = ("{d["code"]}", {d["http"]}, "{d["log_msg"]}")')
lines += ["", " @property", " def http_status(self): return self.value[1]",
" @property", " def log_template(self): return self.value[2]"]
with open("error_codes.py", "w", encoding="utf-8") as f:
f.write("
".join(lines))
print("✅ messages.ja.json / messages.en.json / error_codes.py を生成しました")
レビューチェックリスト
| # | チェック項目 |
|---|---|
| 1 | エラーコードの体系(プレフィックス・番号ルール)が定義されているか |
| 2 | ユーザー向けとログ向けメッセージが分離されているか |
| 3 | ユーザー向けメッセージに技術情報が含まれていないか |
| 4 | ログ向けメッセージに個人情報・パスワードが含まれていないか |
| 5 | HTTPステータスコードとの対応が定義されているか |
| 6 | 多言語対応が必要な場合、全言語のメッセージが定義されているか |