FormatException やパース失敗は、入力文字列と想定フォーマットのズレで起きる。日付・数値・GUID・Enum 変換でよく踏み、ロケールやトリム漏れが原因になりやすい。「例外で落とすか、TryParse で返すか」を先に決める。
先に結論
- 外部入力は
TryParse/モデルバインド検証が基本。Parse 直投げは境界だけ
- 日付はフォーマットと Culture、数値は桁区切り・小数点に注意
- 失敗時は「どの項目のどの値か」をログに残す(値のマスクは適切に)
- API では 400 系で返し、サーバ例外として 500 にしない
よくある原因
- 空文字・空白・null をそのまま Parse
- ロケール差分(小数点がカンマ、日付順が違う)
- ISO 8601 とローカル表記の混在
- 前後の引用符・BOM・不可視文字
- Enum 名の大小文字や数値範囲外
- 複合フォーマット文字列のプレースホルダ不一致(別系統の FormatException)
切り分け
- スタックトレースで Parse/Convert/バインダのどれかを特定
- 入力の長さ・Culture・想定フォーマットをログに出す
- 同じ値を単体テストやスクラッチで TryParse して再現
- フレームワークのモデル検証エラーと、手書き Parse 例外を混同しない
対策
- 境界で TryParse。失敗は業務エラーとして返す
- 日付は
DateTimeOffset と不変フォーマット(Invariant/丸め括弧付きフォーマット)を寄せる
- 数値は Culture を明示。UI 入力と API 入力で方針を分ける
- 文字列.Format/補間の引数個数不一致もテストで防ぐ
ざっくりまとめ
- FormatException は入力と想定形式の不一致が本命
- 外部入力は TryParse+検証。Culture/空白を疑う
- 失敗は 400 相当で返し、どの項目かを残す
関連記事