検証環境: Excel 365 v2509 · Excel 2021 · Excel 2019 · 最終確認 2026-06-08
要点 — On Error は、実行時エラーが起きた 後 にマクロがどう振る舞うかを決めます。既定では処理が止まり、利用者の目の前にエラーダイアログが出ます。On Error はその挙動を変えるスイッチです。書き方はちょうど 3 種類しかなく、選択を誤るとマクロが静かにデータを壊していきます。
Sub ProcessData()
On Error GoTo ErrHandler ' これ以降のエラーはすべてハンドラーへ飛ぶ
Dim ws As Worksheet
Set ws = Sheets("Report") ' "Report" が無ければ下へジャンプ
ws.Range("A1").Value = 100
Exit Sub ' ここで必ず抜ける。さもないとハンドラーに落ちる
ErrHandler:
MsgBox "処理に失敗しました: " & Err.Description
End Sub
3 つの書き方を一か所にまとめると次のとおりです。
On Error GoTo ErrHandler ' エラーをラベル付きハンドラーへ送る ——最も確実な選択
On Error Resume Next ' エラーを無視して次の行を実行 ——忘れると危険
On Error GoTo 0 ' トラップを再び OFF に ——「止めてダイアログを出す」既定へ戻す
メンタルモデル:On Error は「落ちたときにどこへ行くか」を決めるスイッチ
マクロの一行一行が道路を走っているところを思い浮かべてください。ある行が実行時エラー(シートが無い、ゼロ除算、型の不一致)に遭ったときの 既定 の挙動は、急ブレーキです。処理は止まり、Excel は黄色い 実行時エラー '…' のボックスを [デバッグ] / [終了] とともに表示します。開発中のあなたにはそれで構いません。けれど、あなたのツールを使う利用者にとっては、読めないまま行き止まりになるだけです。
On Error は、その急ブレーキの行き先を切り替えるスイッチです。エラーそのものを 防ぐ わけではありません——エラーは依然として起きます——決めるのは 次に制御がどこへ行くか だけです。この捉え直しだけで、混乱のほとんどは解けます。Java や Python のように何かを「キャッチ」しているのではなく、次に落ちたときの行き先を設定しているのです。
このスイッチは、現在のプロシージャの残りの間(あるいは次に切り替えるまで)入りっぱなしになります。そして プロシージャ単位 です——ProcessData で設定したハンドラーは、そこから呼ぶ別の Sub には一切効きません。その Sub が自分で設定しない限り。
たった一つのルール:On Error Resume Next はエラーを「隠す」のであって「処理する」のではない
堅牢なマクロと時限爆弾とを分けるルールがこれです。
On Error Resume Nextは VBA に 「今壊れたものは無かったことにして、そのまま進め」 と命じます。これは症状を黙らせるだけ。問題を直すわけでも、記録することすらしません。
失敗を見込んでいる 一行だけに意図的に使うなら、これは完璧です。しかし不用意に使うと——Sub の冒頭に On Error Resume Next を一つ置いてそのまま忘れる——そのプロシージャ内の すべて のバグを黙らせます。マクロは「動いている」ように見え、半分空欄の結果を書き込み、誰も一か月気づきません。
正しい型は、範囲を狭くする + 直後に必ず確認する + すぐ OFF に戻す、の 3 点セットです。
' 存在するか分からない図形を削除「したい」場面。
On Error Resume Next ' リスクのある一行だけに対して武装する
ActiveSheet.Shapes("OldLogo").Delete
If Err.Number <> 0 Then Err.Clear ' 認識してリセット ——単に図形が無かっただけ
On Error GoTo 0 ' 直ちに解除 ——エラーの無視をやめる
これを安全にしているのは 3 点です。対象が一行だけであること、直後に Err.Number を確認していること(Err オブジェクトを参照)、そして On Error GoTo 0 で解除していること。どれか一つでも欠けると、再びバグを隠す状態に逆戻りします。
二つめの落とし穴:ハンドラーの前に Exit Sub を忘れる
ラベル付きハンドラーは、プロシージャの末尾に置かれた単なるコードにすぎません。本来の処理が終わった後、正常な 経路がそのままハンドラーへ歩み込むのを止めるものは何もありません。
Sub SaveReport()
On Error GoTo ErrHandler
' ... 成功する本来の処理 ...
MsgBox "保存しました。" ' 成功メッセージ
' ⚠ Exit Sub が無い ——処理はそのまま続く...
ErrHandler:
MsgBox "保存に失敗しました。" ' ...そして利用者は両方のメッセージを見る
End Sub
正常に実行できたのに、利用者は「保存しました。」と「保存に失敗しました。」の両方を見ます。直し方はたった一行、ハンドラーのラベルの直前に Exit Sub(または Exit Function)を置くこと。これで正常経路は、落ち込む前にプロシージャを抜けます。この構造的な背骨は VBA エラー処理で扱います。
On Error GoTo 0 ——みんなが忘れる書き方
On Error GoTo 0 は、エラートラップを既定の「止めてダイアログを出す」状態にリセットします。重要な理由は二つです。
- 意図的な
Resume Nextの後、それ以降の本物のバグが飲み込まれないように 無視をやめる ための手段です。 - 開発中は、問題の行で VBA を止めて [デバッグ] を押せるようにする手段です——有効なハンドラーが、犯行現場からあなたを連れ去ってしまうのを防げます。
On Error Resume Next
Set wb = Workbooks("Budget.xlsx") ' 開いているかもしれないし、いないかもしれない
On Error GoTo 0 ' ここからはエラーが再びマクロを止める
If wb Is Nothing Then Set wb = Workbooks.Open("C:\Data\Budget.xlsx")
踏み込んだ判断:Err の確認が無い裸の On Error Resume Next は堅牢さではなくバグ
人が On Error Resume Next に手を伸ばすのは、赤いダイアログが消えるからです。そして「エラーメッセージが無い」状態は「エラーが無い」状態のように 感じられます。違います。声を上げて失敗できないマクロは、信用できないマクロです——その代わりに、あなたのデータの中で静かに失敗していくだけです。
私の経験則はこうです。すべての On Error Resume Next には、数行以内に対になる Err.Number の確認と On Error GoTo 0 が無ければなりません。この二つの相棒を指し示せないなら、あなたはエラーを処理したのではなく、埋めただけです。見込んだ失敗を一つスキップする以上のことをするなら、On Error GoTo Label と本物のハンドラーを使いましょう。
どれをいつ使うか
| やりたいこと | 使うもの | 注意点 |
|---|---|---|
| すべてのエラーを一か所に集めて対処する | On Error GoTo ErrHandler |
ラベルの前に Exit Sub を置く |
| 失敗を見込んでいる 一行をスキップする | On Error Resume Next(狭い範囲) |
Err.Number を確認し、On Error GoTo 0 |
| 無視をやめる/本物の行でデバッグする | On Error GoTo 0 |
無いと Resume Next が武装したまま |
| 修正後に失敗した行をやり直す | Resume(ハンドラー内) |
原因未修正だと無限ループ |
よくある On Error の誤り(と直し方)
| 症状 | 原因 | 直し方 |
|---|---|---|
| マクロは走るのに結果が半分空欄 | On Error Resume Next が入りっぱなしで本物のエラーを飲み込んでいる |
削除する、または一行に絞って On Error GoTo 0 を付ける |
| 成功と失敗のメッセージを両方見る | ハンドラーのラベル前に Exit Sub が無い |
ErrHandler: の直前に Exit Sub を追加 |
| 「ラベルが定義されていません」 | On Error GoTo X なのに、このプロシージャに X: ラベルが無い |
ラベルを追加するか、Resume Next/GoTo 0 を使う |
| ハンドラーは動くが何が壊れたか分からない | Err.Description / Err.Number を一度も読んでいない |
ハンドラー内で Err オブジェクトを読む |
| ハンドラーの後もエラーがマクロを止める | ハンドラーは動いたが Resume も Exit もしていない |
出口を明示する:Resume Next / Resume / Exit Sub |
エラー処理がマクロの大半を占めるなら ——仕事を言葉で伝えるだけでいい
「単純な」マクロのどれだけが配管に化けるかに注目してください。ハンドラーを武装し、Err を確認し、解除し、後始末をし、再開するかどうかを決める。実務のパイプライン——3 つのファイルを取り込み、注文 ID で突き合わせ、不一致に印を付ける——では、エラー処理の足場が、本当に書きたいロジックを上回ることさえあります。ExcelMaster Agent なら、その仕事を自然な日本語で言うだけで、失敗をあらかじめ処理し、ファイルを先にバックアップする Python を生成します——On Error も Resume も、静かなデータ破壊もありません。無料で試す →
関連記事
- VBA エラー処理 — 信頼できるマクロが必ず使うたった一つの型
- VBA の Err オブジェクト — Number・Description と自前エラーの送出
- VBA の Sub とは — プロシージャの呼び出し方と「マクロの正体」
- VBA For ループ — 実務で使う 8 つの例
よくある質問
VBA の On Error は何をしますか?
On Error は、現在のプロシージャで実行時エラーが起きたときの挙動を設定します。既定(処理を止めて 実行時エラー ダイアログを出す)の代わりに、エラーをハンドラーへ送る(On Error GoTo Label)、失敗した行をスキップする(On Error Resume Next)、既定に戻す(On Error GoTo 0)のいずれかを選べます。
On Error Resume Next は悪い習慣ですか?
本質的には違います。ただし、失敗を見込んだ一行だけに範囲を絞り、直後に Err.Number を確認し、On Error GoTo 0 を続ける場合に限ります。プロシージャ全体で入れっぱなしにすると、すべてのエラーを黙らせ、バグを隠して結果を静かに壊します。一般的な処理には On Error GoTo Label を選びましょう。
On Error GoTo 0 と On Error Resume Next の違いは何ですか?
On Error Resume Next はエラーを無視して次の行へ進みます。On Error GoTo 0 はその逆で、エラートラップを OFF にし、次のエラーがマクロを止めて再びダイアログを出すようにします。通常は Resume Next のブロックを解除するために GoTo 0 を使います。
VBA でエラー処理を OFF にするには?
On Error GoTo 0 を使います。現在のプロシージャで有効な On Error Resume Next や On Error GoTo Label の設定をすべて解除し、VBA 既定の「エラーで止まる」挙動に戻します。
On Error は呼び出した別のプロシージャにも効きますか?
いいえ。On Error はプロシージャ単位です。A がハンドラーを設定して B を呼んだ場合、B 内のエラーは A のハンドラーでは捕まりません——ただし B が自前のハンドラーを持たないときは、エラーが A まで伝播します。処理が必要なプロシージャは、それぞれ自分でハンドラーを設定すべきです。
