トップ/記事一覧/Slackの日本語が全部□に文字化けした。原因は自動更新で増えた1行だった
slack-snap-japanese-tofu-fontconfig-sysroot-cover

Slackの日本語が全部□に文字化けした。原因は自動更新で増えた1行だった

朝の自動更新のあと、UbuntuのSlackで日本語だけが全部□になった。英数字と絵文字は無事、OS側の日本語フォントも健全。原因はsnapの新バージョンに追加されたFONTCONFIG_SYSROOTの1行で、フォント探索の起点が日本語フォントを持たない共通部品の箱に閉じ込められていた。切り分けの手順と直し方を実際のコマンド出力付きで記録する。

ラボ2026年7月30日公開 本日更新
目次
この記事のポイント

朝の自動更新のあと、UbuntuのSlackで日本語だけが全部□になった。英数字と絵文字は無事、OS側の日本語フォントも健全。原因はsnapの新バージョンに追加されたFONTCONFIG_SYSROOTの1行で、フォント探索の起点が日本語フォントを持たない共通部品の箱に閉じ込められていた。切り分けの手順と直し方を実際のコマンド出力付きで記録する。

2026年7月30日の朝、UbuntuのSlackを開いたら日本語が一文字残らず□(いわゆる豆腐)になっていました。前日まで普通に読めていたので、こちらは何も触っていません。犯人はその朝に走ったSlackの自動更新で、新しいバージョンに1行だけ増えた設定でした。その1行にたどり着くまでに何を疑って何を確かめたかを、実際に叩いたコマンドと出力そのままで残します。同じ症状で検索してきた方は、最後の「直し方」だけ読んでいただいても構いません。

何が起きたか

症状はSlackのウィンドウ全体に及んでいました。チャンネル名も、メッセージ本文も、日本語の部分だけがすべて□に置き換わっています。一方で英数字は普通に読め、絵文字も色付きで正しく表示されていました。この「日本語だけが消え、英数字と絵文字は無事」という組み合わせが、後から振り返ると最大の手がかりでした。

もう一つ気づいたことがあります。メッセージに添付された画像の中に写っている日本語は、まったく問題なく読めていました。画像はすでに絵として焼き付いているので、パソコン側がどのフォントを持っているかとは無関係です。つまり「Slackが受け取った日本語の文字を、画面に描くところで失敗している」という切り分けがこの時点でできました。文字データそのものが壊れているわけではありません。

まずOSのフォントを疑った

日本語が□になる原因として真っ先に思い浮かぶのは、日本語フォントがOSから消えたことです。Ubuntuのアップデートで何かが外れたのかもしれません。そこでfontconfigの付属コマンドで確認しました。fontconfigは、Linuxで「この文字はどのフォントで描けばいいか」を各アプリに教える案内係です。アプリは自分でフォントファイルを探し回るのではなく、この案内係に聞きに行きます。

$ fc-list :lang=ja | wc -l
81

$ fc-match sans-serif:lang=ja
NotoSansCJK-Regular.ttc: "Noto Sans CJK JP" "Regular"

fc-list :lang=jaは「日本語が描けるフォントを全部挙げろ」、fc-match sans-serif:lang=jaは「日本語のゴシック体を頼まれたら、実際にはどれを渡すのか」を聞くコマンドです。日本語フォントは81件そろっていて、代表として渡されるのもNoto Sans CJK JPという真っ当な日本語フォントでした。OS側はまったく健全です。

実際、同じデスクトップで動いている他のアプリはどれも日本語が普通に表示されていました。壊れているのはSlackだけです。

Slackの中に入って同じことを調べる

ここで環境の話をしておきます。私のSlackはsnap版です。snapは、アプリ本体と必要な部品をひとつの箱に詰めて配るUbuntuの仕組みで、箱の中と外(=OS本体)ではファイルの見え方が変わります。「同じ/usr/share/fontsという住所でも、箱の中から見た時と外から見た時で中身が違う」ということが普通に起こる、と考えてください。

箱の外が健全でも、箱の中が健全とは限りません。snap run --shellを使うと、そのアプリとまったく同じ条件のシェルに入れます。中でさっきと同じ2つのコマンドを叩きました。

$ snap run --shell slack
$ fc-list :lang=ja | wc -l
0

$ fc-match sans-serif:lang=ja
DejaVuSans.ttf: "DejaVu Sans" "Book"

日本語フォントが0件。日本語を頼んでも返ってくるのはDejaVu Sansという、日本語をまったく持っていない欧文フォントです。持っていない文字を描けと言われたフォントは□を出すしかありません。症状が完全に再現しました。ここまでで、原因はSlackの箱の中でフォントが見つからないことだと確定です。

フォントは見えているのに、見つけてもらえない

では箱の中に日本語フォントのファイル自体が届いていないのか。同じシェルの中でフォントの置き場を覗いてみると、意外なことに普通に見えていました。

$ ls /usr/share/fonts/opentype/noto/
NotoSansCJK-Black.ttc      NotoSansCJK-Regular.ttc
NotoSansCJK-Bold.ttc       NotoSerifCJK-Regular.ttc
...

$ fc-query -f "%{family}\n" /usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc
Noto Sans CJK JP
Noto Sans CJK KR
Noto Sans CJK SC

ファイルはある。fc-query(指定した1ファイルの中身を直接読むコマンド)で開けば、中に日本語フォントが入っていることまで確認できる。それなのにfc-listは0件を返す。「見えている」のに「見つけてもらえない」という、いちばん気持ちの悪い状態です。

この時、コマンドを叩くたびに次のエラーが大量に流れていました。

Fontconfig error: No writable cache directories

案内係が作業メモ(キャッシュ)を書き込む場所がない、という訴えです。いかにも怪しく見えたので、書き込み可能な空のフォルダを新しく用意して、そこをキャッシュ置き場に指定し直し、フォント一覧を作り直させてみました。結果は変わらず日本語0件のまま。このエラーは確かに出ているものの、今回の主犯ではありませんでした。派手に出るエラーが原因とは限らない、という当たり前のことを一度回り道して確認したことになります。

決め手はfc-cacheの出力に付いていた接頭辞

その回り道が結果的に当たりを引きました。フォント一覧を作り直すfc-cache -f -v(-vは処理の詳細を出す指定)の出力を眺めていて、行頭に見慣れない接頭辞が付いていることに気づきます。

Font directories:
	/usr/share/fonts
	/usr/share/fonts/truetype
	/usr/share/fonts/truetype/dejavu
	/usr/share/fonts/truetype/noto
[/snap/slack/254/gnome-platform]/usr/share/fonts/truetype/dejavu: caching, new cache contents: 8 fonts, 0 dirs
[/snap/slack/254/gnome-platform]/usr/share/fonts/truetype/noto: caching, new cache contents: 1 fonts, 0 dirs

角括弧の中身/snap/slack/254/gnome-platformが、この案内係にとっての「根っこ」でした。つまり/usr/share/fontsを探せと言われた時、実際に見に行くのは/snap/slack/254/gnome-platform/usr/share/fontsです。住所の頭に別のフォルダが黙って足されている状態で、この「根っこの位置をずらす設定」をsysroot(シスルート)と呼びます。

環境変数を確認すると、はっきり指定されていました。

$ env | grep -i font
FONTCONFIG_FILE=/snap/slack/254/gnome-platform/etc/fonts/fonts.conf
FONTCONFIG_PATH=/snap/slack/254/gnome-platform/etc/fonts
FONTCONFIG_SYSROOT=/snap/slack/254/gnome-platform

このgnome-platformというのは、GUIアプリが共通で使う部品をまとめた別のsnap(共通部品の箱)です。各アプリが同じ部品を重複して抱えなくて済むように用意されています。問題は、その箱に入っているフォントの中身です。

$ find /snap/gnome-46-2404/current/usr/share/fonts -type f
.../truetype/dejavu/DejaVuSans.ttf
.../truetype/dejavu/DejaVuSans-Bold.ttf
(ほかDejaVu計8ファイル)
.../truetype/noto/NotoColorEmoji.ttf

欧文フォントのDejaVuが8ファイルと、絵文字フォントが1ファイル。日本語も中国語も韓国語も1ファイルたりとも入っていません。ここでようやく、最初に感じた違和感がすべて説明できました。英数字が読めたのはDejaVuがあったから。絵文字が色付きで出ていたのはNotoColorEmojiがあったから。そして日本語だけが□になったのは、この箱に日本語フォントが1つも無いからです。OS側に81件そろっていた日本語フォントは、根っこがずらされたせいで最初から探索範囲の外でした。

自動更新で増えていた1行

残る疑問は「なぜ今朝から急に」です。snapは更新の履歴を残しているので、そこを見ました。

$ snap changes
ID   Status  Spawn                   Ready                Summary
230  Done    yesterday at 22:08 JST  today at 10:58 JST   Auto-refresh snap "slack"

今日の10時58分に自動更新が完了しています。時刻もぴったり合いました。snapは1つ前のバージョンをディスクに残しておいてくれるので、新旧2つの設定ファイルを直接見比べられます。

$ grep -E "^base:|FONTCONFIG" /snap/slack/253/meta/snap.yaml
base: core22

$ grep -E "^base:|FONTCONFIG" /snap/slack/254/meta/snap.yaml
base: core24
      FONTCONFIG_PATH: $SNAP/gnome-platform/etc/fonts
      FONTCONFIG_FILE: $SNAP/gnome-platform/etc/fonts/fonts.conf
      FONTCONFIG_SYSROOT: $SNAP/gnome-platform

これが答えです。更新前のリビジョン253(バージョン4.50.143)にはフォント関係の指定が一切ありませんでした。だから案内係は根っこをずらされず、OS本体の/usr/share/fontsをそのまま見に行き、日本語フォントを見つけられていたのです。更新後のリビジョン254(バージョン4.51.180)で3行が追加され、そのうちのFONTCONFIG_SYSROOTが探索の根っこを共通部品の箱の中に閉じ込めました。

この更新では土台もcore22からcore24へ、共通部品の箱もGNOME 42用からGNOME 46用へ切り替わっています。大きめの土台移行のついでに入った設定が、日本語環境だけを踏み抜いた形です。なお古い方の共通部品の箱にも日本語フォントは入っていません(DejaVu 6ファイルと絵文字1ファイルのみ)。根っこをずらす設定さえ無ければ問題にならなかった、という点が重要です。

直し方: 前のバージョンに戻して自動更新を止める

原因がアプリ側の設定である以上、こちらでフォントを足して解決することはできません。根っこの先にある共通部品の箱は書き換え不可の領域なので、そこに日本語フォントを置くという手が使えないからです。取れる現実的な手は、更新前に戻すことでした。

sudo snap revert slack        # 1つ前のリビジョンに戻す
sudo snap refresh --hold slack # 自動更新を止める(戻した直後にまた上書きされるのを防ぐ)

revertは残っている1つ前のリビジョンに戻すコマンドで、ダウンロードのやり直しは発生しません。戻しただけだと次の自動更新で同じバージョンが降ってくるので、--holdで止めるところまでが1セットです。戻した後に、箱の中で同じコマンドを叩いて確認しました。

$ snap run --shell slack
$ echo "[$FONTCONFIG_SYSROOT]"
[]
$ fc-list :lang=ja | wc -l
84

根っこをずらす設定は消え、日本語フォントも見つかるようになりました。Slackを起動し直したところ、日本語は元通り表示されています。

注意点として、この記事を書いている時点では安定版もベータ版も問題のバージョンです。つまり修正版はまだ出ていないので、--holdを外すとまた文字化けします。解除する時は、sudo snap refresh --unhold slackを叩く前に、更新後のバージョンで直っているかを確認してからにしてください。バージョンを古いまま止め続けたくない場合は、Slack公式サイトが配布している.deb版に乗り換えるという選択肢もあります。こちらはsnapの箱に入らないので、根っこがずらされること自体が起こりません。

同じ症状にぶつかった時に見る場所

いちばん時間を溶かしたのは「ファイルは見えているのに見つけてもらえない」の一点でした。lsで存在を確認できてしまうと、つい「ファイルはあるのだから別の原因だ」と考えてしまいます。しかし探索の根っこをずらす設定が挟まっていると、自分の目で見えている場所とプログラムが探しに行く場所が食い違います。この手のズレは、エラーメッセージではなく処理の詳細ログの行頭に、静かに書かれていることがあります。

もう一つは、派手なエラーを主犯と決めつけないことです。今回は「キャッシュを書ける場所がない」という警告が大量に出ていましたが、それを解消しても症状は1ミリも動きませんでした。仮説を1つ潰すたびに症状が変わらないことを確認する、という手順を踏んだからこそ、そちらは枝葉だと判断できました。

そして、身に覚えのない不具合が朝いちで出たら、まず更新履歴を見ることです。今回はsnap changesで完了時刻を見た瞬間に、原因の範囲が「今朝の自動更新で変わったもの」に一気に狭まりました。自動更新は放っておくと更新してくれる便利な仕組みですが、その日の朝に何が入れ替わったかを自分で確認できる状態にしておく価値は大きいと感じます。

avatar-m-1

堀川 慎

Backend Engineer / AWS / Django / Go