Upgrade to Pro — share decks privately, control downloads, hide ads and more …

protojson における文字化けの扱い

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest. →
Avatar for Kazu Kazu
November 09, 2026

protojson における文字化けの扱い

https://layerx.connpass.com/event/408206/

layerx.go 登壇資料 5分LT

Avatar for Kazu

Kazu

November 09, 2026

Other Decks in Programming

Transcript

  1. アジェンダ 今日の話 持ち帰ってほしいこと 文字列をバイト数で切ると文字が壊れるが、その場では err も panic も出ない。 壊れた文字列を、JSON 変換や

    DB 保存が err にするのか、黙って書き換えるのかを知っておく 1. 前提:バクラク勤怠の構成と申請 2. 起きたこと:本番で 1 件の 500 と、その原因 3. 本題: の文字化けの扱い 4. まとめ protojson © LayerX Inc. 2
  2. 自己紹介 自己紹介 Kazu(@KazuLayerX) LayerX で バクラク勤怠 を作っています 2026 年 4

    月に新卒で入社 インターンを含めて、LayerX に入社するのは 4 回目 © LayerX Inc. 3
  3. 前提 バクラク勤怠の構成:DB に保存する直前で 画面 React protojson を通る 勤怠サービス protojson.Marshal →

    MySQL → GraphQL → → BFF(Backend for Go。proto の RPC で受けて DB に保存する直前に JSON 型の列 Frontend) proto の型のまま処理する proto の型を JSON にする Go の中では proto の型のまま持ち回り、JSON になるのは DB に保存する直前だけ © LayerX Inc. 4
  4. 前提 申請では「種別」と「コメント」を書く 項目 種別 内容 何の申請か(有給・残業・打刻修正など) コメント なぜ申請するか。自由に書ける 最大 400

    文字。超えたら後ろを切って ... を付ける 今日の事件は、この コメント で起きた © LayerX Inc. 例 午前休 私用のため午前休を取得 6
  5. 起きたこと 原因:「400 文字で切る」つもりが、バイトで切っていた 仕様「最大 400 文字。超えたら後ろを切って ... を付ける」の実装(397 + ...

    の 3 = 400) も [:n] も、数えているのは文字数ではなくバイト数 日本語は多くの文字が 3 バイト → 文字の途中で切れても、panic も err もない len ※ 影響範囲は調査済みで、影響はごく一部の申請に限られる(修正済み) © LayerX Inc. 9
  6. 起きたこと バイトで切ると、日本語 1 文字が途中で切れる 例:コメントの 397 バイト目が「取得」の「得」の 1 バイト目だったとき 元の文字列

    "..." を付けた結果 取 E5 8F 96 得 E5 ✂ BE 97 … … 96 E5 2E 2E 2E は「あと 2 バイト続く」の合図なのに、次に 2E ( . )が来た → 正しい UTF-8 ではない文字列(文字化け) ができあがる E5 © LayerX Inc. 10
  7. 本題:protojson の文字化けの扱い 文字化けした文字列は、Go の中を素通りした 処理 切る comment[:397] proto の型に詰める 永続化処理に渡す

    └ INSERT 中の protojson.Marshal © LayerX Inc. 結果 エラーなし エラーなし エラーなし invalid UTF-8 → 500 中身( fmt の %q で表示) 午前休を取\xe5..." "… 午前休を取\xe5..." "… 午前休を取\xe5..." "… DB には何も保存されない 12
  8. 本題:protojson の文字化けの扱い protojson は UTF-8 を確かめてから JSON にする proto3 の

    string も JSON も 「UTF-8 であること」が前提 だから protojson は文字化けした文字列を通さない この 500 は、 protojson のおかげで出たエラーだった © LayerX Inc. 13
  9. 本題:protojson の文字化けの扱い もし encoding/json だったら、文字化けしたまま DB に保存されていた 午前休を取 E5 ...

    渡したもの … DB に保存されるもの … 午前休を取 U+FFFD(置換文字) ... (v1)は 黙って U+FFFD に置き換える。 err == nil 500 にならず、文字化けしたまま画面に表示される。私たちは気づけない encoding/json ※ Go 1.27 から GOEXPERIMENT なしで使える © LayerX Inc. encoding/json/v2 は、既定でエラーにする 14
  10. 本題:protojson の文字化けの扱い 補足:MySQL は sql_mode 同じ文字列を VARCHAR に INSERT すると

    sql_mode 結果 次第で結果が真逆になる ERROR 1366: Incorrect string value: '\xE5...' strict(本番環境の設定) エラーで止まる。何も保存されない Warning 1366 (エラーではない) strict でない 壊れたバイトから後ろが黙って消える(「…午前休を取」までしか残らない) MySQL 8.0.46 で確認 © LayerX Inc. 15
  11. まとめ まとめ:文字化けしたとき、err を返すのは誰か 文字列をバイト数で切ると文字が壊れるが、その場では err も panic も出ない。 壊れた文字列を、JSON 変換や

    DB 保存が err にするのか、黙って書き換えるのかを知っておく err を返さない err を返す comment[:n] encoding/json © LayerX Inc. protojson (v1) encoding/json/v2 直し方 文字数で数える 文字単位で切る 16