エラーコード定義の位置づけ

エラーコードは「システムの言語」だ。エラーが発生したとき、ユーザー・サポート担当・開発者が同じコードを使って話せることが重要だ。設計段階でコード体系・メッセージの粒度を決めておかないと、実装が進むにつれてコードが乱立する。

💡 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 / messages.en.json)
// 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 — エラーコード定義ファイルの自動生成

Python — エラーコード定義から多形式ファイルを自動生成
"""
エラーコード定義(単一 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ログ向けメッセージに個人情報・パスワードが含まれていないか
5HTTPステータスコードとの対応が定義されているか
6多言語対応が必要な場合、全言語のメッセージが定義されているか