VBA のエラー処理モデル
VBA にはJavaやPythonのような try-catch-finally 構文がありません。代わりに On Error ステートメントでエラー発生時の挙動を3パターンから選択します。
| ステートメント | 動作 | 用途 |
|---|---|---|
On Error GoTo ラベル | エラー発生時に指定ラベルへジャンプ | 一般的なエラー処理 |
On Error Resume Next | エラーを無視して次の行を実行 | エラーの存在確認・部分スキップ |
On Error GoTo 0 | エラー処理を無効化(既定に戻す) | Resume Next の解除 |
On Error GoTo — ラベルジャンプ型
最も基本的で推奨されるパターンです。エラー発生時に指定したラベルに処理が移ります。
Option Explicit
Sub OpenFileExample(ByVal filePath As String)
Dim wb As Workbook
On Error GoTo ErrHandler ' エラーハンドラを登録
Set wb = Workbooks.Open(filePath)
' ── 正常処理 ──
MsgBox "開きました: " & wb.Name
wb.Close SaveChanges:=False
Exit Sub ' ← 正常終了時はここで抜ける(ErrHandler を実行しない)
ErrHandler:
MsgBox "エラー " & Err.Number & ": " & Err.Description, vbCritical
' 必要に応じてリソース解放
If Not wb Is Nothing Then wb.Close SaveChanges:=False
End Sub
⚠️ Exit Sub を忘れずに
正常処理の末尾に Exit Sub(または Exit Function)を書かないと、正常終了時もエラーハンドラが実行されてしまいます。必ずセットで記述してください。
On Error Resume Next — スキップ型
エラーが発生しても次の行に進みます。使いどころは限定的で、エラーの存在チェックや「なければ無視」の処理に限定するのが鉄則です。
Option Explicit
' ── シート存在確認の例 ──
Function SheetExists(ByVal sheetName As String) As Boolean
Dim ws As Worksheet
On Error Resume Next
Set ws = ThisWorkbook.Worksheets(sheetName)
On Error GoTo 0 ' ← 必ず解除する
SheetExists = Not (ws Is Nothing)
End Function
' ── 使用例 ──
Sub CheckSheet()
If SheetExists("データ") Then
MsgBox "シートがあります"
Else
MsgBox "シートが存在しません"
End If
End Sub
⚠️ On Error Resume Next を広範囲に使うと危険
On Error Resume Next をプロシージャ全体にかけると、すべてのエラーが握りつぶされます。必要な箇所だけに絞り、直後に On Error GoTo 0 で解除してください。
Err オブジェクト
エラーハンドラ内では Err オブジェクトからエラーの詳細を取得できます。
| プロパティ / メソッド | 内容 |
|---|---|
Err.Number | エラー番号(0 はエラーなし) |
Err.Description | エラーメッセージ |
Err.Source | エラーが発生したオブジェクト名 |
Err.Clear | Err 情報をリセット |
Err.Raise Number, Source, Description | 意図的にエラーを発生させる |
Option Explicit
Sub ErrObjectExample()
On Error GoTo ErrHandler
' 意図的にエラーを発生させる
Err.Raise 9, "ErrObjectExample", "独自エラーメッセージ"
Exit Sub
ErrHandler:
Debug.Print "番号: " & Err.Number ' → 9
Debug.Print "内容: " & Err.Description ' → インデックスが有効範囲にありません
Debug.Print "発生元: " & Err.Source ' → ErrObjectExample
Err.Clear ' エラー情報をクリア
End Sub
クリーンアップパターン(Finally相当)
Javaの finally に相当するリソース解放処理を実現するパターンです。
Option Explicit
Sub ProcessWithCleanup()
Dim conn As Object ' DB接続などのリソース
Dim errNum As Long
Dim errMsg As String
On Error GoTo ErrHandler
Set conn = CreateObject("ADODB.Connection")
conn.Open "接続文字列"
' ── メイン処理 ──
' ...
Cleanup:
' 正常・エラー問わず必ず実行
If Not conn Is Nothing Then
If conn.State = 1 Then conn.Close ' 接続中なら閉じる
Set conn = Nothing
End If
If errNum <> 0 Then
MsgBox "エラー " & errNum & ": " & errMsg, vbCritical
End If
Exit Sub
ErrHandler:
errNum = Err.Number
errMsg = Err.Description
Resume Cleanup ' ← Cleanup ラベルへジャンプ
End Sub
✅ ポイント
エラー情報を変数に退避してから Resume Cleanup でクリーンアップラベルに移動するパターンが定石です。Resume Cleanup を使うと On Error ハンドラ内でもエラーを再発生させずにジャンプできます。
入れ子プロシージャでのエラー伝播
呼び出し先(子)でハンドルされなかったエラーは、呼び出し元(親)のエラーハンドラに伝播します。
Option Explicit
Sub Parent()
On Error GoTo ErrHandler
Call Child ' Child 内でエラーが発生
Exit Sub
ErrHandler:
MsgBox "Parent がキャッチ: " & Err.Description
End Sub
Sub Child()
' On Error がない → エラーは Parent に伝播する
Dim x As Long
x = 1 / 0 ' ゼロ除算エラー
End Sub
まとめ:使い分けフロー
| 状況 | 推奨パターン |
|---|---|
| 一般的なエラー処理 | On Error GoTo ErrHandler |
| オブジェクトの存在チェック | On Error Resume Next → On Error GoTo 0 |
| リソースを必ず解放したい | Cleanup ラベル + Resume Cleanup |
| 意図的なエラー通知 | Err.Raise |
✅ 次の章では…
PART 03 では モジュール分割設計 を解説します。標準モジュール・クラスモジュール・ThisWorkbook の役割を整理し、大規模マクロを保守しやすく設計する方法を紹介します。