跳轉到

Twirp Error Handling

概念概覽

mapError 覆蓋不全(Fallthrough 問題)

核心知識

mapError 覆蓋不全(Fallthrough 問題)

mapError 若未涵蓋所有 domain error,未匹配的 error 會 fallthrough 成 generic twirp.Internal,client 無法得到有意義的錯誤碼。

症狀:新增了 domain error(如 ErrUnsupportedCurrencyErrHeroNotOwned)但忘記更新 mapError修復:每新增 domain error 必須同步加入 mapError 的 case,建議加入 code review checklist 或 linter 規則。

err.Error() 洩漏內部細節

// WRONG: 洩漏 wrap chain 給 client
return twirp.NewError(twirp.InvalidArgument, err.Error())

// CORRECT: 固定字串,細節留在 server log
return twirp.NewError(twirp.InvalidArgument, "invalid argument")

err.Error() 可能包含 stack trace、DB query、內部 struct 名稱等,直接回傳給 client 是資訊洩漏漏洞。

規範建議

  • mapError 回傳訊息:固定字串,不用 err.Error()
  • 詳細錯誤資訊:用 log.Error() 記錄 server side,不傳給 client
  • mapError 維護:與 domain error 定義放同一 PR,強制 review

經驗教訓

  • mapError 是 domain error 與 RPC error code 的對應表,必須與 domain error 同步維護

  • err.Error() 回傳給 client 在 wrap error 模式下尤其危險,wrap chain 會洩漏內部路徑

常見陷阱

  • 新增 domain error 時只測試了 happy path,未測試 error mapping,導致 fallthrough 進 production

  • 用 fmt.Errorf("操作失敗: %w", err) wrap 後再 .Error() 回傳,會把完整 chain 暴露

最佳實踐

  • mapError 使用固定字串,詳細 error log server side

  • 每個 domain error 都要有對應的 mapError case,缺一不可

  • 考慮用 exhaustive switch linter 確保 mapError 不漏 case

相關概念

相關視角

以下頁面與本概念共享主題,但從不同角度切入。保留獨立視角同時提供交叉參考:

來源 Sessions

日期 Session 貢獻摘要

| 2026-03-17 | 10eef6a0-3a55-4d63-981c-6bc79aff1880 | 發現 mapError 兩類問題:domain error 覆蓋不全導致 fallthrough 為 generic error,以及 err.Error() 直接回傳給 client 洩漏內部細節 |


本概念頁面由 Semi-Brain Wiki 系統自動維護

最後更新: 2026-03-17