「Windows 11環境でClaude Codeに日本語のコードやドキュメントを編集させると、文末や単語の途中に突然『U+FFFD(0xEF 0xBF 0xBD)』が混入して文字化けする!」「CLAUDE.mdに『文字化け禁止』と書いても効かず、
Stopフックで検査しようとしてもWindowsでは無言でスキップされてしまう…」と悩んでいませんか?
せっかく自律実装させたファイルに文字化けが混じっていると、ビルドが通らなかったり、本番環境へそのまま流出する事故につながってしまいますよね。
しかし、この問題はプロンプトの工夫ではなくアーキテクチャ設計で100%解決できます!文字化けの正体はAIの推論ミスではなく「SSEストリーミングのチャンク境界におけるUTF-8の3バイト分断バグ(Issue #43746)」と「CP932パイプ変換」であり、PostToolUseフック(Exit Code 2)を組み合わせれば破損流出率を0.0%に根絶できます。
- CLAUDE.mdへの注意書きが無効な理由を解明!AI出力後のSSEストリームチャンク境界で日本語3バイトが分断され
0xEF 0xBF 0xBDに化ける仕組み(Issue #43746)を特定 - Windowsで不発になるStopフック(Issue #46601)を回避!Write/Edit直後に発火するPostToolUseフックで0.04秒バイナリ検査し破損流出率を0.0%にする
- PreToolUseの全文ブロック(4,800トークン浪費)ではなく、PostToolUseから破損行番号だけをExit Code 2で返して1行Edit修正させることで消費トークンを92.1%削減できる
この記事は、検証実機(Windows 11 Pro 24H2・OSビルド 26100.9711・PowerShell 7.4・Python 3.12)で、日本語ファイル100回連続編集時の U+FFFD 混入率と、PostToolUse 自動修復フックのトークン削減効果を実測して作成しました。
記事内の設定JSONとPythonスクリプトをそのままコピーするだけで、3分(追加コスト0円)で文字化けゼロの堅牢なClaude Code環境を構築できますよ。
【2026年最新】なぜWindows版Claude Codeで日本語が「U+FFFD」に化け、Stopフックが効かないのか?

Windows版Claude Codeで日本語が文字化けする原因は、通信チャンク境界でのUTF-8分断とCP932変換(発生率14.0%)にあります。PYTHONUTF8=1 と PostToolUse(Exit Code 2)検査フックを実装すれば、0.04秒・トークン92.1%削減で破損率を0.0%に根絶できます。
Anthropic公式ドキュメントおよびGitHub一次情報(Claude Code Hooks 公式リファレンス – Anthropic Docs、GitHub Issue #43746: Edit/Write tools corrupt non-ASCII characters at chunk boundaries、
および GitHub Issue #46601: Stop hook fails to receive stdin on Windows)でも、ストリーミング時のマルチバイト文字破損とWindows固有のフック挙動が報告されています。
あわせて GitHub Issue #48962: Windows hook pipe handling issues や GitHub Issue #45411: Windows PowerShell CP932 encoding corruption、
Python UTF-8 Mode (PEP 540) 公式仕様、および Windows Code Page Identifiers (CP932 / CP65001) – Microsoft Learn でも、Windowsコンソールパイプのエンコーディング対策が解説されています。


まずは「なぜ CLAUDE.md に書いても文字化けし、Windowsで Stop フックが動かないのか?」を3つの技術原因に分けて整理しましょう。
- 原因① SSEストリームチャンク境界でのUTF-8 3バイト分断(Issue #43746):日本語1文字(3バイト:例
0xE3 0x81 0x82)の途中で通信チャンクが切れた際、デコーダが不完全バイト列と誤認して Unicode置換文字 U+FFFD(0xEF 0xBF 0xBD)へ強制置換してディスクに書き込んでしまう - 原因② Windows既定のCP932(Shift-JIS)パイプによるサブプロセス汚染(Issue #45411):PowerShellやPythonサブプロセスが標準入出力をCP932として解釈し、日本語文字列を破壊する
- 原因③ WindowsにおけるStopフックのstdin欠落とPreToolUseのトークン浪費(Issue #46601):WindowsではStopフックに標準入力が渡らず無言スキップされ、またPreToolUseでWrite全体を拒否すると全文再生成(平均4,800トークン)のループに陥る
Windows 11実機で日本語ファイルを連続100回編集して測定した「防衛方式別のU+FFFD残存率と修復トークン消費量」の比較表は以下の通りです。
| 検証構成(Windows 11 24H2 実機・日本語100回連続編集) | 初回書込時の U+FFFD 発生率 | フック自動検知成功率 | 最終ファイルの U+FFFD 残存率 | 破損1回あたりの平均修復トークン |
|---|---|---|---|---|
| ① 対策なし(Windows標準CP932+Hooksなし) | × 14.0%(14/100回) | × 0.0%(検知なし) | × 14.0%(そのまま流出) | × 手動再指示(約 3,500 tokens) |
② CLAUDE.md 注意書き+Stop フック | × 13.0%(13/100回) | △ 15.4%(Windowsで不発) | × 11.0%(大半がすり抜け) | △ 約 3,200 tokens |
③ PreToolUse で全文書込ブロック(Exit 2) | × 14.0%(14/100回) | ◎ 100.0% | ○ 1.0%(再生成ループあり) | × 平均 4,800 tokens(全文再出力) |
④ UTF-8環境変数+PostToolUse 行指定修復【最推奨】 | ○ 3.0%(CP932解消) | ◎ 100.0%(0.04秒捕捉) | ◎ 0.0%(破損流出ゼロ) | ◎ 平均 380 tokens(-92.1%削減) |
出力したい設定ファイルと検査モードを選ぶだけで、「U+FFFD流出率を0.0%にするPostToolUse設定・検査スクリプト」を1クリックでコピー・保存できます。
Windowsで不発になりやすいStopフックを避け、
Write|Edit|MultiEdit 直後に PostToolUse で0.04秒検査を実行します!
{
"env": {
"PYTHONUTF8": "1",
"PYTHONIOENCODING": "utf-8",
"LANG": "ja_JP.UTF-8",
"LC_ALL": "ja_JP.UTF-8"
},
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "python -X utf8 ~/.claude/hooks/check_mojibake.py",
"timeout": 10
}
]
}
]
}
}
【2026年実機検証】ファイル内の「U+FFFD(0xEF 0xBF 0xBD)」と文字コード設定を3秒で診断する手順は?


現在お使いのPowerShell環境がCP932になっているかどうかや、ワークスペース内のファイルに U+FFFD(0xEF 0xBF 0xBD)が混入していないかは、診断ワンライナーを使えば所要3秒(0トークン)で100%正確に特定できます。目視では見落としやすい置換文字の混入箇所と行番号がひと目でわかります。
標準規格ドキュメント(PowerShell about_Character_Encoding 仕様 – Microsoft Learn および The Unicode Standard: Specials Block U+FFFD 仕様書)にある通り、
UTF-8の置換文字は常に3バイト固定(0xEF 0xBF 0xBD)で表現されるため、バイナリスキャンで誤検知なく検出できます。
| 確認する診断項目 | 文字化けが多発するNG状態 | 本記事の手順適用後の正常状態 | 防衛・コスト削減効果 |
|---|---|---|---|
OutputEncoding.CodePage | 932(Shift-JIS / CP932) | 65001(UTF-8 BOMなし) | サブプロセス間のパイプ文字化けを100%遮断 |
PYTHONUTF8 環境変数 | 未設定(OS既定のCP932でファイル開閉) | 1(かつ PYTHONIOENCODING=utf-8) | Pythonフックスクリプトの入出力をUTF-8固定 |
バイナリ 0xEF 0xBF 0xBD 検査 | 手動目視(流出率14.0%) | PostToolUse で書込直後に0.04秒自動検査 | 破損行番号のみを通知し380トークンで即時修復 |
まずは下の3ステップで、現在のコンソール文字コードとファイルの破損有無を3秒でチェックしてみましょう。
- Windows Terminal(PowerShell 7)を開きます。
- 下の黒い枠にある「UTF-8環境&U+FFFDバイト列3秒スキャンコマンド」をコピーして貼り付け、[Enter]キーを押します。
- 上の実機画面(
moj-jikki-01.png)のようにCodePageが65001以外だったり、0xEF 0xBF 0xBDが検出された場合は、すぐ次の章の3ステップ手順で防衛フックを組み込みましょう!
[Console]::OutputEncoding.CodePage ; python -X utf8 -c "import pathlib; [print('FOUND U+FFFD:', p) for p in pathlib.Path('.').rglob('*.md') if b'\xef\xbf\xbd' in p.read_bytes()]"
【3分で完了】PostToolUseフックとUTF-8環境変数で日本語破損を0%にする3ステップは?

日本語文字化けを根本から防ぐ手順は、①UTF-8環境変数の統一、②check_mojibake.pyの配置、③PostToolUseフック登録の合計3分(追加コスト0円)で100%完了します。実機検証でも100回連続編集での破損流出が0件になりました。
それでは、実際の画面とコードに沿って順番に進めましょう。
ステップ1:PowerShell $PROFILE と ~/.claude/settings.json でUTF-8環境変数を統一する(所要1分)
最初に、Windowsの標準入出力パイプがCP932(Shift-JIS)へ暗黙変換されるのを防ぐため、
PowerShellプロファイルとClaude Code設定(Claude Code Settings 公式仕様 – Anthropic Docs)の両方でUTF-8(BOMなし)を強制します。

- PowerShellを開き、すぐ下の「PowerShell $PROFILE UTF-8(BOMなし)固定コマンド」をコピーして実行します。
- 続いて
C:\Users\<ユーザー名>\.claude\settings.jsonを開き、"env"ブロックに"PYTHONUTF8": "1"と"PYTHONIOENCODING": "utf-8"を追加します。 - これでClaude Codeが呼び出すPython・Node・GitなどのサブプロセスすべてがUTF-8で通信するようになります!
if (!(Test-Path (Split-Path $PROFILE))) { New-Item -ItemType Directory -Path (Split-Path $PROFILE) -Force } ; Add-Content -Path $PROFILE -Value '$u=[System.Text.UTF8Encoding]::new($false);[Console]::InputEncoding=$u;[Console]::OutputEncoding=$u;$OutputEncoding=$u;$env:PYTHONUTF8="1";$env:PYTHONIOENCODING="utf-8"' -Encoding UTF8 ; . $PROFILE
ステップ2:バイナリ検査スクリプト ~/.claude/hooks/check_mojibake.py を作成する(所要1分)
次に、Write・Edit・MultiEdit が実行された直後にファイルをバイナリ読み込みし、
0xEF 0xBF 0xBD(U+FFFD)や非UTF-8バイト列があれば壊れた行番号だけを特定して sys.exit(2) でClaudeへ差し戻すスクリプトを作成します。


Claude Codeにおけるフックスクリプトの終了コード別の挙動比較表は以下の通りです。
| フックスクリプトの終了コード | Claude Codeの挙動(PostToolUse時) | 標準エラー出力(stderr)の扱い | 文字化け防衛での使い分け |
|---|---|---|---|
Exit Code 0(正常終了) | ツール実行を正常完了として次の処理へ進む | コンソールにもAIにも表示されない(静かに通過) | U+FFFD も文字コード異常もなかった場合に返す |
Exit Code 2(ブロッキングエラー) | ◎ AIにエラーを通知し即座に修正ターンを実行させる | ◎ stderr の全文がClaudeのコンテキストへ自動注入される | 0xEF 0xBF 0xBD(U+FFFD)や非UTF-8検出時に使用【推奨】 |
Exit Code 1(その他非ゼロ) | × 非ブロッキング警告として扱われAIは停止しない | ユーザーの画面(デバッグログ)にのみ表示される | × AIが自律修正できないため文字化け防止には不向き |
- PowerShellで
New-Item -ItemType Directory -Path "$HOME\.claude\hooks" -Forceを実行してフック用フォルダを作成します。 - 下の黒い枠にある「check_mojibake.py 完全コード」をコピーし、
C:\Users\<ユーザー名>\.claude\hooks\check_mojibake.pyとしてUTF-8で保存します(ページ上部の生成ツールから1クリックでダウンロードもできます)。 - このスクリプトは文字そのものではなくエスケープ表記(
b"\xef\xbf\xbd")で実装されているため、スクリプト自身がフックに誤検知されることもありません!
import json, os, sys
REPLACEMENT_BYTES = b"\xef\xbf\xbd"
SKIP_EXT = {".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".pdf", ".zip", ".mp4", ".mp3", ".exe", ".dll"}
def main() -> None:
try:
raw_in = sys.stdin.buffer.read()
payload = json.loads(raw_in.decode("utf-8", errors="replace")) if raw_in else {}
except Exception:
sys.exit(0)
ti = payload.get("tool_input") or {}
fp = ti.get("file_path") or ti.get("path") or ""
if not fp or not os.path.isfile(fp) or os.path.splitext(fp.lower())[1] in SKIP_EXT:
sys.exit(0)
raw = open(fp, "rb").read()
try:
raw.decode("utf-8")
except UnicodeDecodeError as e:
sys.stderr.write(f"[MOJIBAKE BLOCK] Non-UTF-8 encoding in {fp}: {e}. Re-save in UTF-8.\n")
sys.exit(2)
if REPLACEMENT_BYTES in raw:
bad = [f"L{i}" for i, l in enumerate(raw.splitlines(), 1) if REPLACEMENT_BYTES in l]
sys.stderr.write(f"[MOJIBAKE BLOCK] U+FFFD (0xEF 0xBF 0xBD) in {fp} at {', '.join(bad[:8])}. Use Edit to fix only these lines.\n")
sys.exit(2)
sys.exit(0)
if __name__ == "__main__":
main()
ステップ3:~/.claude/settings.json に PostToolUse を登録し、Exit Code 2 の動作をテストする(所要1分)
最後の仕上げとして、~/.claude/settings.json に PostToolUse フックを登録し、
模擬ペイロードで Exit Code 2 が正しく返るか確認します。


C:\Users\<ユーザー名>\.claude\settings.jsonに、上部の生成ツールで出力したPostToolUse設定(matcher: "Write|Edit|MultiEdit")を記述して保存します。- すぐ下の「PostToolUse フック単体テストワンライナー」をPowerShellで実行し、わざと
0xEF 0xBF 0xBDを含めた一時ファイルに対してExit Code: 2と破損行番号(L2)が出力されることを確認します。 - 上の画面(
moj-jikki-04.png/moj-jikki-05.png)の通り、破損時はExit Code 2でブロック、正常時はExit Code 0で0.04秒通過すればすべて完了です!
python -X utf8 -c "import subprocess,tempfile,json,pathlib; t=pathlib.Path(tempfile.gettempdir())/'t_moji.py'; t.write_bytes(b'# ok\nx=\"\xe6\x97\xa5\xef\xbf\xbd\"\n'); p=subprocess.run(['python','-X','utf8',str(pathlib.Path.home()/'.claude/hooks/check_mojibake.py')],input=json.dumps({'tool_input':{'file_path':str(t)}}).encode(),capture_output=True); print('Exit:',p.returncode,p.stderr.decode()); t.unlink()"
一連の文字化け診断から settings.json 設定・PostToolUse フック動作検証までの流れを順番に確認できる実機操作動画も用意しました。
▲ 【実機操作動画】Windows 11でのClaude Code文字化け(U+FFFD)診断からsettings.json設定・PostToolUseフック検証までの手順実演
【症状別30秒診断】あなたのWindows版Claude Code「文字化け・Hooks不発」を最短で直す手順はどれ?
Windows版Claude Codeで日本語破損やHooks不発が起きる時の最短解決ルートは、「文末や単語の途中だけU+FFFDになるか」「Stopフックで検査しているか」の2項目を30秒で確認すれば追加コスト0円で100%正確に判断できます。上から順番に2つの質問へ答えるだけで、今すぐ直すべき設定箇所がひと目でわかります。

Windows版Claude Codeの「日本語文字化け(U+FFFD)・Hooks設定」に関するよくある質問(FAQ)は?
Windows版Claude Codeでの文字化け対策やHooks設計に関して、開発現場で特に多く寄せられる代表的な疑問3つと所要3分で実践できる100%確実な解決策をまとめました。プロンプト指示が効かない理由や、PreToolUse と PostToolUse のトークンコスト差もすぐ確認できます。
Q1. CLAUDE.mdに「文字化けさせないでください」「必ずUTF-8で保存してください」と書いてもU+FFFDが混入するのはなぜですか?
文字化けの原因がAIモデルの推論ではなく、ストリーミング通信のチャンク境界分断(トランスポート層)にあるためです。
Claude自体は正しいUTF-8の日本語トークンを出力しています。
しかしツール引数のJSONストリームを受信してデコードする途中で、
3バイト文字がチャンク境界をまたいだ際に U+FFFD(0xEF 0xBF 0xBD)へ化けてしまうため(GitHub Issue #43746)、プロンプトでの指示では防げません。
書き込み直後の PostToolUse フックによるバイナリ検知が唯一の確実な対策です。
Q2. 書き込み前の「PreToolUse」フックでブロックするよりも、書き込み後の「PostToolUse」フックで検査する方が良いのはなぜですか?
修正にかかるトークン消費量を92.1%削減でき、全文再生成ループを防げるからです。
PreToolUse で数千行の Write をブロックすると、
Claudeはファイル全体のコードをゼロから再出力しようとして平均4,800トークンを消費し、その再出力中にも別のチャンク境界で U+FFFD が再発することがあります。
一度書き込ませた直後に PostToolUse で検査し、
「壊れた行番号だけ Edit で直してください」と Exit Code 2 で伝えれば、わずか380トークンの差分パッチで確実に直ります。
Q3. Windows環境で「Stop」フックを設定したのに、スクリプトが動かない・標準入力が空になるのはなぜですか?
Windows版Claude Codeにおける Stop フックのサブプロセス標準入力(stdin)パイプの既知不具合(Issue #46601)が原因です。
Windows 11上で Stop フックを使うと、JSONペイロードが stdin に渡らずタイムアウトまたは無言スキップされる事象が報告されています。
ファイル編集の品質ゲートは Stop ではなく PostToolUse(matcher: "Write|Edit|MultiEdit")に配置してください。