AIに作ってもらったスクリプトを走らせたら、途中まで結果が出たところで「UnicodeEncodeError」と赤い文字が出て止まった。処理は終わったのか、失敗したのか。それすら分からない。
この記事が扱うのは、計算まで終わっていて最後の出力だけが落ちるケースです。エラー最終行が UnicodeEncodeError で、codec の名前が cp932 なら、それに当たります(処理の途中のログ出力で落ちている場合は、その先の処理は動いていません)。
⚠️ この記事の情報は2026年8月時点のものです。検証環境:Windows 11 / Python 3.14.3 / PowerShell。出力をファイルへリダイレクトした状態で再現しました。PYTHONIOENCODING や PYTHONUTF8 が既に設定されている環境では再現しません。記事に出てくる株のシステムは相場を観測・研究するためのもので、自動発注はしません(read-only)。実際のお金での発注はしていません(仮想発注のみ・実発注なし)。内容は確認でき次第、随時更新します。
この記事で分かること
「昨日まで動いていたのに、ログに絵文字を足した日から落ちるようになった」。そういう状態の人向けです。
- エラー文のどこを読めば「出力の段で落ちた」と判別できるか
- 対処3つ(出力側の保険/実行時の設定/コンソール側の設定)と、それぞれの限界(chcp はこのエラーには効きません)
- 自動実行に載せれば結果と成否の判定材料を同時に失う書き方を、監査と自動検査が実運用前に見つけた実録
先に結論です。文字を消して逃げるのではなく、出力の書き出し方だけを段階的に落とすのが安全でした。日本語のまま出す → 駄目ならエスケープした形で出す → それでも駄目ならバイト列で直接書く。見た目は順に読みにくくなりますが、中身は一文字も減りません(エラーが二度と出なくなるという意味ではありません)。
【早見表】症状から、最初に打つ一手へ
| いまの症状 | 疑うこと | 最初の一手 |
|---|---|---|
| 途中まで出力されて赤い文字で止まる | 書き出す段で落ちている | エラー最終行の「codec」の名前を見る |
| エラー文に「cp932」と書いてある | 出力先がコンソール以外(ファイルへのリダイレクト・パイプ) | 対処2の環境設定をまず試す |
画面では動くのに > out.txt を付けると落ちる | リダイレクトでcp932に切り替わっている | これが本症状。対処1を入れる |
| 絵文字やチェックマークを足した直後から起きた | その記号がCP932に無い | 対処1の3段の保険を入れる |
| 自分のPCでは動くのに人のPCで落ちる | 環境設定に頼っている | 対処1へ移す(設定は配れない) |
| 自動実行だけ静かに失敗する | ログへのリダイレクト経由で走っている | 対処1(必須)+対処2。対処3は効かない |
症状:処理は終わっているのに、書き出す瞬間だけ落ちる
この症状のいちばんの厄介さは、失敗の場所と原因の場所が離れていることです。
データを集める、計算する、結果をまとめる。そこまでは全部うまくいっています。最後に「じゃあ出力しますね」となった瞬間だけ、変換に失敗して例外(エラー)が飛ぶ。「重い処理の途中で落ちた」ように見えて、実際は「軽いはずの最後の1行で落ちた」わけです。
途中まで文字が出ているのは「途中まで成功した」のではありません。1行ずつ書き出していて、CP932に無い文字が現れた行で止まった、というだけです。
先に切り分け:落ちるのは「出力先がコンソールではないとき」
ここは最初に押さえておくと迷いません。この例外が出るのは、出力先が画面(コンソール)そのものではないときです。具体的にはファイルへのリダイレクト、他のプログラムへのパイプ、そしてそれらを使う自動実行(タスクスケジューラでログへ書き出す構成など)です。
逆に、PowerShellの黒い画面でそのまま python your_script.py と打った場合は、いまのPythonは画面へUTF-8で書き出すので、この例外は出ません(フォントが対応していないと□に見えることはありますが、落ちはしません)。
だから切り分けは1行で済みます。
# 画面では動くのに、これにすると落ちる → 本記事の症状
python your_script.py > out.txt
「手元では平気なのに、自動実行に載せた途端に落ちる」の正体もこれです。ただし自動実行が危ないのは、無人だからではありません。たいてい結果をログファイルへ書き出す(>> log.txt)か、パイプで受け取る形にしているからです。手元で試したところ、ウィンドウを隠して起動しただけならコンソールは割り当てられたままで、この例外は出ませんでした。落ちる/落ちないを分けるのはリダイレクトの有無です。
エラー文のどこを読むと「出力で落ちた」と分かるか
長いエラー文を全部読む必要はありません。見るのは最後の1行だけです。
UnicodeEncodeError: 'cp932' codec can't encode character '\u2705' in position 128: illegal multibyte sequence
読み方は3か所です。
- Encode(エンコード=書き出し)なら出力側の問題。Decode(デコード=読み込み)なら別の話で、ファイルを読む側を疑います。
- codec の名前が「cp932」なら、日本語Windowsで出力を書き出す変換に失敗しています。
- character の後ろが犯人の文字です。
'\u2705'のように番号で書かれていることが多く、この例はチェックマークの絵文字(✅)にあたります。末尾のillegal multibyte sequenceは「その文字コードにその文字が無い」という意味です。
自分のエラーと見比べるときは、この最終行を丸ごと突き合わせてください(position の数字は出力の中身によって変わります)。エラー文の上のほうを見れば、落ちた行として print(...) が出ているはずです。ここまで確認できたら診断は終わり。データ処理は無罪、犯人は出力です。
絵文字・チェックマーク・記号を足した直後に始まることが多い
「昨日まで平気だった」には理由があります。CP932は日本語(ひらがな・カタカナ・漢字)はきちんと扱えるからです。つまり日本語だけのログなら、この問題は何年でも表に出ません。
ところが、ログを見やすくしようとして次のような文字を足すと、その日から落ち始めます。
- ✅ ❌ ⚠️ 🚀 などの絵文字(AIが書いたスクリプトはこれを好んで入れます)
- ✓ ✔ ☑ ✖ などのチェック・バツ記号(見た目が似た別コードの文字が混ざりやすい)
- — (em dash・
U+2014)、▶ ➡ ⭐ などの記号(全角ダッシュ ―U+2015とは別物です)
逆に、★ → ⇒ ㎡ ℃ はCP932に収録されているので落ちません(手元で実測しました)。記号だからという理由で疑われがちですが、これらは無罪です。だから「記号を使っているから怪しい」で当たりをつけるより、エラー最終行の character の後ろに出ている番号を見るほうが確実です。
「見やすくした」つもりが、そのまま地雷になっている。よくある話です。
なぜWindowsだけ起きるのか(既定の文字コード CP932)

文字コード(character encoding)は、文字を数字に置き換えるときの対応表です。
いまのPythonはスクリプトの中でUTF-8という広い対応表を使います。絵文字もハングルも載っている大きな辞書です。問題は書き出すときで、出力先がコンソール以外のとき、Pythonは日本語Windowsの既定である CP932 という狭い対応表を使います。日本語の実務のために作られた古い辞書で、絵文字は載っていません。
逆に言うと、出力先が本物のコンソールのときは、いまのPythonは画面へUTF-8で直接書き出します。だから「黒い画面では出ないのに、リダイレクトや自動実行では出る」という、いかにも理不尽な出方をします。
起きているのは翻訳の失敗です。スクリプトが「✅を書き出して」と渡す。CP932が「その文字はうちの辞書に無い」と返す。Pythonは黙って捨てることを嫌って、例外を出して止まる。
MacやLinuxでこの症状が出ないのは、既定の辞書が最初からUTF-8だからです。「ネットの記事のとおりにやったのに落ちる」の多くはこの差で、書いた人はWindowsを想定していません。スクリプトの中身は最初から最後まで正しい。壊れているのは受け渡しの一点だけです。
いちばん怖いのは「結果」と「終了コード」を同時に失うこと
手で実行しているうちは、まだ幸せです。そもそも画面へ出している間は落ちませんし、リダイレクトして落ちても赤い文字が見えるので「あ、落ちたな」と分かります。問題は自動実行に載せたときです。誰も画面を見ていません。
ここで終了コード(exit code)という言葉が出てきます。プログラムが終わるときに残す「成功か失敗か」の番号で、0なら成功、それ以外は失敗という約束です。タスクスケジューラや自動化の仕組みは、この番号を見て次の判断をします。
実録:自動実行で「結果と終了コードを同時に失う」一歩手前で止めた話
正直に書くと、この失敗は実際には起きていません。同じ書き方は以前の監査で、合成したCP932の出力先に流して再現させて見つけていました。今回のファイルはその再発防止の検査に引っかかった段階で、CP932の出力先へ流す前に塞いでいます。以下はその「一歩手前」の記録です。
私が使っている株のシステム(相場を観測・研究するためのもので、自動発注はしません。仮想発注のみ・実発注なし)に、「決めた安全の境界が口約束ではなく機械で守られているか」を測り、結果をJSON(機械が読める形のデータ)で出す点検ツールがあります。
そのツールが、いちばん素直な書き方で出力していました。print(json.dumps(..., ensure_ascii=False)) です。日本語をそのまま読める形で出すための書き方で、悪気はありません。修正のときに追加された関数の説明文には、何が起きるかが日本語ではっきり書かれていました。この書き方はCP932の出力先でUnicodeEncodeErrorを出し、JSONの判定と終了コードの両方を同時に失わせる、と。
両方、というのが効きます。JSONは途中で切れるので読めない。例外で止まるので終了コードも本来のものにならない。呼び出した側に返るのは「何かに失敗したらしいが、何を測ったのかは分からない」という残骸だけ。点検のためのツールが、点検結果を運べない。
しかも一度きりの指摘ではありませんでした。監査で2ラウンド続けて、別のファイルから同じ書き方が見つかりました。だから個別のバグとして直すのをやめて、「出力はこう書く」という規約と、それを機械的に見張る検査に移しました。今回の1件も、見つけたのは人の目ではなくその検査です。
修正した時点で、同じ実装の保険関数が、点検ツールを置いているフォルダの8ファイルに置かれていました(説明文は簡略版のものもあります)。さらにテスト側の2本が、その保険を通さない出力が残っていないかを機械的に走査していました。
正直に書いておくと、これは誰かの古いミスを直したものではありません。その作業中に自分たちで新しく作り込んでしまった不具合2件のうちの1件を、原因のところだけ最小限で直したものです。直したあとに該当の検査が通ったことが記録に残っています。規約があっても、新しく書いたファイルではまた素直に書いてしまう。それが実態でした。
だから「たまたま通った日」を成功と数えない
この症状は、出力に含まれる文字しだいで出たり出なかったりします。日本語だけの日は通る。エラー詳細に「✅」が混ざった日だけ落ちる。つまり「昨日は成功した」の中身は、実力ではなくたまたま危ない文字が出力に入らなかっただけかもしれません。
だから判定基準を変えます。「今日は例外が出なかった」ではなく、「出力に保険が入っているか」で見る。前者は運の記録で、後者は仕組みの記録です。
対処1:出力側に3段の保険を入れる(内容は落とさず、表現だけ段階的に落とす)

いちばん確実なのはこれです。実際に採用された形も、この3段でした(③は、既存の実装のうち堅いほう=buffer があるか確かめてから書くやり方に合わせたうえで、先に吐き切る処理と、buffer が無かったときの退避先をこの記事で足しています)。
import json
import sys
def safe_print_json(payload):
# ① まず、日本語のまま読める形で出す
try:
print(json.dumps(payload, ensure_ascii=False, indent=2))
return
except UnicodeEncodeError:
pass
# ② 出力先が受け取れない文字を \uXXXX の形に逃がして出す(純ASCIIになる)
try:
print(json.dumps(payload, ensure_ascii=True, indent=2))
return
except UnicodeEncodeError:
pass
# ③ 最後の一枚。文字コード変換を通さずUTF-8のバイト列で直接書き出す
sys.stdout.flush() # 出力順が崩れないよう先に吐き切る
buf = getattr(sys.stdout, "buffer", None) # buffer が無い環境もある
data = json.dumps(payload, ensure_ascii=True, indent=2).encode("utf-8") + b"\n"
if buf is not None:
buf.write(data)
buf.flush()
else:
sys.stderr.write(data.decode("utf-8")) # それも無ければ標準エラーへ退避
方針は一行で言えます。段階的に劣化させるが、内容は劣化させない。
①から③へ落ちるにつれて、人間にとっての読みやすさは下がります。②では日本語が \u30c6\u30b9\u30c8(=「テスト」)のような番号の羅列になり、③は装飾なしのバイト列です。でも、含まれている情報は3つとも同じ。諦めているのは見た目だけです。
役割も書いておきます。②は出力が純ASCIIだけになるので、普通はここで成功します。CP932に無い文字が1つも残らないからです。③は環境が特殊なときのための最後の一枚で、実際にはめったに到達しません。到達するのは、標準出力が「strict(厳格)な文字コード変換をする、差し替えられた出力先」になっている場合に限られます。逆に、pytestの出力捕捉やJupyterのように文字列をそのまま受け取る出力先では①が成功するので、③には来ません。ただしそういう環境では buffer が存在しないことがあるため、③は必ず存在確認をしてから書きます。ここで二次災害を起こすと、保険を入れた意味がなくなります。
やってはいけないのは「落ちるなら危ない文字を消しちゃえ」という直し方です。出力そのものを削る実装にすると、後から何が起きたか追えなくなります。落とすのは表現。中身は落とさない。
この形の良いところは、スクリプトの中で完結することです。相手のパソコンの設定に何も要求しません。人に配るもの、自動実行に載せるものは、これ以外を頼りにしないほうが安全でした。
対処2:実行時の環境設定でUTF-8にする
いますぐ自分の手元で通したいだけなら、これが早いです。Pythonに「出力はUTF-8で扱って」と伝えます。出力先がファイルでもパイプでもUTF-8になるので、リダイレクトで落ちる症状はこれで止まります(実測で確認しました)。
# PowerShell の場合(そのウィンドウの中だけ有効)
$env:PYTHONUTF8 = "1"
python your_script.py
# コマンドプロンプトの場合
set PYTHONUTF8=1
python your_script.py
# 1回だけ試すなら、実行時のオプションでも同じことができます
python -X utf8 your_script.py
PYTHONUTF8=1 はPythonのUTF-8モードを入れるスイッチです。似たものに PYTHONIOENCODING=utf-8 もありますが、まずはUTF-8モードから試すのが分かりやすいと思います。
限界もはっきりしています。この設定はそのウィンドウの中だけで、閉じれば消えます。システムの環境変数に登録すれば残りますが、それはあなたのパソコンだけの話。スクリプトを渡した相手には何の効果もありません。「私の環境では動くのに」の温床です。
対処3:chcp は「文字化け」用であって、このエラーには効かない
検索するとよく出てくるのがこれです。画面のほうの辞書を差し替えるコマンドです。
chcp 65001
先に結論を書きます。chcp 65001 は画面の文字化け(□=豆腐)対策であって、UnicodeEncodeError の対策にはなりません。
手元で実測しました。chcp 932 と chcp 65001 のそれぞれで、出力をファイルへリダイレクトしてPythonを走らせています。
chcp 932 → python の出力先の文字コード = cp932
chcp 65001 → python の出力先の文字コード = cp932 ← 変わらない
どちらも cp932 のままで、chcp 65001 にしても例外は同じように出ました。リダイレクトしたときのPythonは、画面のコードページではなくWindows側の既定の文字コードを見ているからです。そして画面へそのまま出しているときは、そもそもこの例外が出ません。つまり chcp は、このエラーが起きる場面では効かず、起きない場面でしか出番がないということになります。
そのうえ、次の限界もあります。
- そのウィンドウを閉じると元に戻る。毎回打つことになります。
- フォントが対応していないと絵文字が□(豆腐)のまま。文字化け対策としても万全ではありません。
- 同じ画面で動かしている他の古いプログラムの表示が崩れることがある。巻き添えが出ます。
- 配布先のパソコンには強制できない。
「画面の見た目を直したい」ときの道具、という線引きで使います。落ちるのを止めたいなら対処1か対処2です。
早見表:自分だけで使う/人に配る/自動実行に載せる、で選び方が変わる
3つの対処に優劣はありません。用途で決まります。
迷ったら対処1です。対処2は、対処1を入れるまでの応急処置と考えると整理しやすくなります(対処3はこのエラーには効きません)。
| 使い方 | まず打つ手 | 理由 |
|---|---|---|
| 自分のPCで一度動けばいい | 対処2(環境設定) | スクリプトを触らずに済む。効果はその場限りでよい |
| スクリプトを人に渡す | 対処1(3段の保険) | 相手の設定に期待できない。中に入っているものだけが確実 |
| 毎日の自動実行に載せる | 対処1(必須)+対処2(補助) | 結果と終了コードを失うと、成否の判定材料ごと消える |
| チームで共通のルールにしたい | 対処1を出力の書き方として統一 | 2回目が出た時点で、個別のバグではなく規約の対象 |
AIに直してもらうときの頼み方(そのまま貼れる1行)
「エラーが出ました、直してください」だけだと、絵文字を消す方向の修正が返ってくることがあります。どう直すかまで指定したほうが早い。
このスクリプトの標準出力を、出力先がCP932(ファイルへのリダイレクトやタスクスケジューラ)でも落ちないようにしてください。①まずそのまま出す ②UnicodeEncodeErrorを捕まえてASCIIエスケープの形で出す ③それでも駄目なら標準出力のバイト列へUTF-8で直接書き込む、という3段のフォールバックにしてください。③では先にflushし、
sys.stdout.bufferが無い環境も想定して存在確認をしてから書き、無ければ標準エラーへ退避してください。出力の内容は削らず、表現だけを段階的に落としてください。
直ったら、もう一言足すと再発が減ります。
同じフォルダの他のファイルにも、同じ形の print が残っていないか探して、同じ書き方に揃えてください。
私の場合は、全ファイルを機械的に走査する検査を先に置いていたので、新しく書いたファイルでうっかり素直に書いた1件も、その場で検査に引っかかりました。人力の目視や grep ではなく、検査に置いておくのが効きます。エラー対処全般の進め方はClaude Codeエラー対処法|症状別の原因と解決手順にまとめてあります。
非エンジニアが得た教訓
- 「動いた」には環境がくっついている。設定で直したものは、設定ごと渡さないと相手の手元で再現しない。
- 失敗は最後に出てくる。出力の段で落ちるので、原因が実際よりずっと手前にあるように見える。エラー文の最終行を先に読む。
- 直す方向は「消す」ではなく「落とす」。表現だけを段階的に落とせば、読みにくくなっても情報は残る。
- 2回目が出た時点で、規約にする対象。個別に直し続けるより、書き方を1つ決めて検査に見張らせるほうが結局早い。
- 規約があっても、新しいファイルではまた素直に書いてしまう。だから人の注意力ではなく、検査(テスト)で拾う側に置く。
まとめ
UnicodeEncodeErrorは、処理の失敗ではなく受け渡しの失敗です。スクリプトの中はUTF-8、日本語Windowsの既定はCP932。この辞書の差に、絵文字やチェックマークが引っかかっています。落ちるのは出力先がコンソールではないとき、つまりファイルへのリダイレクト・パイプ(自動実行はたいていこのどちらかを使っています)です。手元で通したいだけなら環境設定(対処2)で足ります。chcp(対処3)はこのエラーには効きません。人に渡すもの、自動で回すものなら、出力側に3段の保険(対処1)を入れておく。
いちばん怖いのは、エラーが出ることではありませんでした。結果と成否の判定材料を同時に失って、成功したのか失敗したのかも分からなくなることでした。保険は結果を守るためというより、判断できる状態を守るために入れています。
関連記事
- 日本語CSVがAIツールで読み込めない5つの原因|症状から引ける確認リスト(今回とは逆の「読み込み側」で文字コードにつまずいたときはこちら)
- Claude Codeエラー対処法|症状別の原因と解決手順(エラー全般の切り分け方)
- Claude CodeのWindowsインストール手順(Windows特有の詰まりどころをまとめています)
無料テンプレート配布のお知らせ
Claude Codeを安全・便利に使うための設定テンプレート(CLAUDE.md)を無料配布しています。メールアドレスをご登録いただくと、すぐにダウンロードリンクをお送りします。
免責事項
本記事は執筆時点(2026年8月)の情報に基づく、筆者個人の体験の記録です。記事中の自動売買システムに関する記述は、特定の投資手法や自動売買の利用を推奨するものではありません。投資には元本割れのリスクがあり、最終的な判断はご自身の責任で行ってください。また、本記事ではセキュリティに関わる話題に触れていますが、悪用防止の観点から、具体的な脆弱性や攻撃手法の詳細は記載していません。AIツールの仕様は予告なく変更される場合があります。最新情報は各公式ドキュメントをご確認ください。本記事の内容を用いて生じたいかなる損害についても、筆者は責任を負いかねます。


コメント