検証環境: Excel 365 v2509 · Excel 2021 · Excel 2019 · 最終確認 2026-06-08
要点 — 実行時エラーが起きると、VBA はただ一つのグローバルオブジェクト——Err——に、その「墜落」について知っているすべてを書き込みます。ハンドラーの中でこれを読んで対処を決めます。さらに Err.Raise で書き込めば、自前のエラーを送出することもできます。
Sub ReadPrice()
On Error Resume Next
Dim price As Double
price = CDbl(Range("A1").Value) ' A1 が数値でなければ失敗
If Err.Number <> 0 Then
MsgBox "エラー " & Err.Number & ": " & Err.Description
Err.Clear ' 次の確認をきれいにするためリセット
End If
On Error GoTo 0
End Sub
オブジェクト全体を一か所にまとめると次のとおりです。
Err.Number ' エラーコード ——0 は「エラーなし」
Err.Description ' 人が読めるメッセージ
Err.Source ' 誰が発生させたか(プロジェクト名/オブジェクト名)
Err.Raise 513 ' 自分でエラーを送出する
Err.Clear ' Err をきれいな状態に戻す
メンタルモデル:Err は「直前の墜落」のブラックボックス
Err は、常に存在するただ一つのグローバルオブジェクトです。マクロの フライトレコーダー だと考えてください。実行時エラーが起きた瞬間、VBA は制御をハンドラーへ飛ばす前に、3 つの事実をここへ書き込みます。
Err.Number— 数値のコード(1004、13、9…)。0は「何も問題は起きていない」を意味します。Err.Description— 赤いダイアログに出るのと同じ文言(「型が一致しません」「インデックスが有効範囲にありません」)。Err.Source— どのプロジェクトまたはオブジェクトが発生させたか。
Err オブジェクトはセッション全体で 一つ だけで、保持するのは 直近の エラーです。だからこそ、何を 読むかと同じくらい いつ 読むかが重要で——そして自動でクリアされるのです(後述)。
たった一つのルール:Err.Number こそが「本当に失敗したか?」を知る唯一の確かな手段
On Error Resume Next の後、コードは行が成功してもしなくても走り続けます。どちらが起きたかを知る 唯一 の方法は、Err.Number を読むことです。
On Error Resume Next
Set wb = Workbooks("Budget.xlsx") ' このブックはもう開いている?
If Err.Number = 0 Then
MsgBox "すでに開いています。"
Else
Err.Clear
Set wb = Workbooks.Open("C:\Data\Budget.xlsx")
End If
On Error GoTo 0
Err.Number の確認が無い Resume Next は無駄です。VBA に失敗を無視せよと命じておきながら、失敗が起きたことに自分が気づけません。この確認こそが処理の本体 です。これは On Error Resume Next と対になるルールで——両者は二つで一組としてしか機能しません。
数値が違えば問題も違うので、特定の コードで分岐させることもできます。
Select Case Err.Number
Case 0: ' エラーなし
Case 9: MsgBox "そのシートまたはインデックスは存在しません。" ' インデックスが有効範囲にない
Case 13: MsgBox "その値は正しい型ではありません。" ' 型の不一致
Case 1004: MsgBox "Excel がその操作を拒否しました。" ' 一般的な自動化エラー
Case Else: MsgBox "予期しないエラー " & Err.Number & ": " & Err.Description
End Select
落とし穴:Err は思いがけないタイミングで自分自身をクリアする
Err は、あなたが用済みになるまで値を保持してはくれません。VBA は次の いずれか が起きると、自動的に Number = 0 へリセットします。
- 任意の
On Errorステートメント(On Error GoTo 0を含む) ResumeまたはResume NextExit Sub/Exit Function- 次の実行時エラー(追記ではなく上書き)
したがって、これらの後で番号や説明が必要なら——記録する、後で表示する、上位へ渡す——ハンドラーが始まった瞬間に、自分の変数へ取り込んでおきましょう。
ErrHandler:
Dim errNum As Long, errMsg As String
errNum = Err.Number ' 今すぐ取り込む
errMsg = Err.Description
On Error Resume Next ' ← この行で Err は消える...
Application.ScreenUpdating = True ' ...だから後始末はもう Err を読めない
LogToSheet errNum, errMsg ' Err.* ではなく保存したコピーを使う
「エラーログにエラー 0 と出る」という不具合報告のほとんどは、このたった一つの罠が原因です。
Err.Raise で自前のエラーを送出する
Err を読むのは、このオブジェクトの半分にすぎません。もう半分は 書き込む こと——VBA のルール違反だけでなく、あなたの ルールが破られたときに、意図的にエラーを送出することです。
Function NetPrice(gross As Double, taxRate As Double) As Double
If taxRate < 0 Or taxRate > 1 Then
Err.Raise vbObjectError + 513, "NetPrice", _
"taxRate は 0 から 1 の間でなければなりません。指定値: " & taxRate
End If
NetPrice = gross / (1 + taxRate)
End Function
Err.Raise Number, Source, Description は本物の実行時エラーを発生させます——呼び出し側の On Error ハンドラーは、組み込みエラーとまったく同じように捕まえます。カスタムエラーには vbObjectError + n(n は 513 から 65535)を使いましょう。この定数は、VBA がシステムコード用に予約している 0〜512 の範囲から十分に外してくれるので、本物のコードと衝突しません。
踏み込んだ判断:エラーコードを返すのは「願い」、エラーを送出するのは「強制」
多くの VBA は、番兵値を返すことで「検証」したつもりになります——-1、False、空文字列を返し、すべての呼び出し側がそれを確認してくれると信じる。確認しません。半年後、誰かがあなたの関数を呼び、-1 を無視し、それで割り算します。
Err.Raise は、その選択肢ごと奪います。送出されたエラーは静かに無視できません——ハンドラーに当たるか、マクロを止めるかのどちらかです。それこそが要点です。Err.Number を読めるようになればエラー処理が「できる人」になりますが、不正な 入力やビジネスルール に対して自前のエラーを送出することこそが、あなたのコードを「礼儀正しいだけ」から「守りが堅い」へ変えます。下流で結果を壊しかねない値なら、フラグを返して祈るのではなく——送出しましょう。
よくある Err の誤り(と直し方)
| 症状 | 原因 | 直し方 |
|---|---|---|
| ログがいつも「エラー 0」 | Resume/On Error/後始末が消した後で Err を読んだ |
先に Err.Number / Err.Description を変数へ保存する |
Resume Next が「何も捕まえない」 |
リスクのある行の後で Err.Number を確認していない |
If Err.Number <> 0 Then … を追加 |
| カスタムエラーがシステムエラーと衝突 | Err.Raise 5 のような小さな生の数値を使った |
Err.Raise vbObjectError + 513 以上を使う |
| 2 回目の確認が古いエラーで発火 | 1 件目を処理した後に Err.Clear を忘れた |
対処し終えたら一度 Err.Clear を呼ぶ |
Err.Description が空 |
Err.Clear やリセットの後で読んだ |
クリアする 前 に説明を読む |
エラー配管を手書きするのはやめて ——ルールを言葉で伝えるだけでいい
堅牢な VBA の半分はこれです。Err.Number を読み、説明を保存し、不正なデータには自前のエラーを送出し、クリアし、また繰り返す。必要ではあるけれど、退屈です。ExcelMaster Agent なら、「税率が 0 から 1 の間にあるか検証して、外れていたら分かりやすいメッセージで止めて」 と自然な日本語で言うだけ——生成された Python が、ファイルを先にバックアップしたうえで、エラーを送出して報告してくれます。無料で試す →
関連記事
- VBA の On Error とは — Resume Next と GoTo、マクロがバグを隠す理由
- VBA エラー処理 — 信頼できるマクロが必ず使うたった一つの型
- VBA の Function とは — 戻り値とユーザー定義関数(UDF)
- VBA For ループ — 実務で使う 8 つの例
よくある質問
VBA の Err オブジェクトとは何ですか?
Err は、直近の実行時エラーに関する情報を保持するグローバルオブジェクトです。主なメンバーは Err.Number(エラーコード、0 = エラーなし)、Err.Description(メッセージ)、Err.Source(発生元)です。エラーハンドラーの中でこれを読み、どう対処するかを決めます。
VBA でエラー番号を確認するには?
Err.Number を読みます。On Error Resume Next の後で If Err.Number <> 0 Then を判定すれば、直前の行が失敗したかどうかが分かります。値が 0 ならエラーは起きていません。Select Case Err.Number で、9(インデックスが有効範囲にない)や 13(型の不一致)など特定のコードごとに違う対応をすることもできます。
Err オブジェクトはいつリセットされますか?
任意の On Error ステートメント、Resume/Resume Next、Exit Sub/Exit Function、そして次のエラーによる上書きで、自動的にリセットされます。後で値が必要なら、Err.Number と Err.Description を直ちに自分の変数へコピーしてください。Err.Clear で手動リセットすることもできます。
VBA でカスタムエラーを発生させるには?
Err.Raise Number, Source, Description を使います。カスタムエラーには vbObjectError + n(n は 513〜65535)を使います。例:Err.Raise vbObjectError + 513, "MyFunc", "入力が不正です"。こうするとシステムエラー用に予約された 0〜512 の範囲を避けられ、呼び出し側のハンドラーが組み込みエラーと同じように捕まえられます。
Err.Clear と On Error GoTo 0 の違いは何ですか?
Err.Clear は Err オブジェクトのプロパティをきれいな状態に戻しますが、エラートラップのモードは変えません。On Error GoTo 0 は トラップのモード を既定(エラーで止まる)に戻し——その副作用として Err もクリアします。同じハンドラー内で Err を再利用するには Err.Clear を、エラーの無視をやめるには On Error GoTo 0 を使います。
