見出し画像

VBAエラー処理3パターン比較──マクロの"突然停止"を95%防いだ実践テクニック

納品前夜、マクロが止まった


あれは3年前の金曜夜だった。

クライアント先で動いていた請求書自動作成マクロが、本番データを流した瞬間に止まった。画面には「実行時エラー '1004'」の文字。原因は、1,200件中たった1件だけ入っていた空白セルだった。

正直、血の気が引いた。テスト環境では完璧に動いていたのに。

「エラー処理、ちゃんと入れておけばよかった」──この後悔が、私のVBAコードを根本から変えた。あの日から、マクロが予期せず止まる事故はほぼゼロになっている。

この記事では、VBAのエラー処理3パターンを比較しながら、「マクロの突然死」を防ぐ具体的な方法を話す。


そもそもVBAのエラー処理、なぜ後回しにしがちなのか


「とりあえず動くものを作りたい」って気持ち、わかる。

Excel VBAを書く人の多くは専業プログラマーじゃない。経理の人、営業事務の人、総務の人。目の前の手作業をなんとか自動化したくてコードを書いている。エラー処理なんて後回しになって当然だと思う。

ただ、ここが落とし穴だったりする。

エラー処理なしのマクロは、想定外のデータが1件でも混じると即停止する。私の経験だと、業務マクロが止まる原因の8割は「想定外のデータ」だった。空白セル、全角数字、日付のフォーマット違い。こういう"ちょっとした例外"でマクロは簡単に死ぬ。


VBAエラー処理の3パターン、ざっくり整理


VBAには大きく3つのエラー処理パターンがある。

パターン1:On Error Resume Next(エラーを無視して続行)


vb
Sub サンプル1_ResumeNext()
    Dim i As Long

    On Error Resume Next  ' エラーが出ても次の行へ進む

    For i = 2 To 100
        Cells(i, 3).Value = Cells(i, 1).Value / Cells(i, 2).Value
    Next i

    On Error GoTo 0  ' エラー無視を解除
End Sub
```

これは「エラーが起きても止まらず次の行へ進む」という指示。一番シンプルで、一番危険なパターンでもある。

なぜ危険か。エラーが起きたことに気づけないから。ゼロ除算が起きても、型の不一致が起きても、何事もなかったかのように処理が進む。結果、出力データが壊れていても誰も気づかない。

私も最初はこれを多用していた。そしたら「計算結果がおかしい」とクライアントから連絡が来て、原因調査に丸一日かかった。Resume Nextで握りつぶされたエラーを追跡するのは本当につらい。

使っていい場面: オブジェクトの存在チェックなど、エラーが起きること自体が「情報」になる場面だけ。

vb
' シートが存在するか確認する例
Dim ws As Worksheet
On Error Resume Next
Set ws = ThisWorkbook.Sheets("集計")
On Error GoTo 0

If ws Is Nothing Then
    MsgBox "「集計」シートが見つかりません", vbExclamation
    Exit Sub
End If
```

こういう「あるかないか調べたいだけ」のときは便利。ただし、`On Error GoTo 0` で必ずエラー無視を解除すること。これを忘れると、以降のコード全体がエラーを握りつぶす爆弾になる。


パターン2:On Error GoTo ラベル(エラー発生時にジャンプ)


vb
Sub サンプル2_GoToラベル()
    On Error GoTo エラー処理

    Dim wb As Workbook
    Set wb = Workbooks.Open("C:\売上データ\2024年3月.xlsx")

    ' ここにメインの処理を書く
    wb.Sheets(1).Range("A1:D100").Copy ThisWorkbook.Sheets(1).Range("A1")
    wb.Close SaveChanges:=False

    Exit Sub  ' ←これを忘れると、正常時もエラー処理に突入する

エラー処理:
    MsgBox "エラーが発生しました" & vbCrLf & _
           "エラー番号: " & Err.Number & vbCrLf & _
           "内容: " & Err.Description, vbCritical
End Sub
```

これが一番よく使われるパターン。エラーが起きたら指定したラベルにジャンプして、そこでエラー内容を表示したり、ログに書いたりできる。

ここで余談なんだけど、`Exit Sub` を書き忘れる人がめちゃくちゃ多い。私も最初やらかした。書き忘れると、正常に処理が終わったのにエラーメッセージが表示されるという謎の挙動になる。「バグです!」と報告が来て、原因が `Exit Sub` の書き忘れだったときの恥ずかしさといったら。

使っていい場面: ファイルを開く、外部データベースに接続する、印刷するなど、外部リソースに依存する処理全般。


パターン3:Errオブジェクトを組み合わせた本格的なエラー処理


vb
Sub サンプル3_本格エラー処理()
    On Error GoTo エラー処理

    Dim i As Long
    Dim errCount As Long
    errCount = 0

    For i = 2 To 1000
        On Error Resume Next
        Cells(i, 4).Value = _
            Application.WorksheetFunction.VLookup( _
                Cells(i, 1).Value, Sheets("マスタ").Range("A:C"), 3, False)

        If Err.Number <> 0 Then
            Cells(i, 5).Value = "エラー: " & Err.Description
            errCount = errCount + 1
            Err.Clear  ' エラー情報をリセット
        End If
        On Error GoTo エラー処理  ' エラーハンドラを再設定
    Next i

    If errCount > 0 Then
        MsgBox errCount & "件のエラーがありました。E列を確認してください", vbInformation
    End If

    Exit Sub

エラー処理:
    MsgBox "想定外のエラーが発生しました" & vbCrLf & _
           "行番号: " & i & vbCrLf & _
           "エラー: " & Err.Number & " - " & Err.Description, vbCritical
End Sub
```

これが私のおすすめ。Resume Nextで個別のエラーを拾いつつ、Errオブジェクトで内容を記録し、想定外のエラーはGoToラベルでキャッチする。3つのパターンのいいとこ取りだ。

`Err.Number` でエラーの種類がわかるし、`Err.Description` で内容もわかる。`Err.Clear` でリセットすれば次のループに影響しない。

冒頭の請求書マクロも、このパターンに書き直したら、1,200件中エラーのある行だけスキップして残りを正常処理できるようになった。止まらない。しかもどこでエラーが出たか一目瞭然。


3パターン、どう使い分けるか


結論から言うと、「パターン3をベースにして、場面に応じてパターン1・2を混ぜる」のが正解だと思っている。

**Resume Next単体で使うケース**
→ オブジェクトの存在確認、1〜2行で完結する処理のみ。必ず直後にOn Error GoTo 0を書く。

**GoToラベルで十分なケース**
→ ループのない一本道の処理。ファイルを開いて、加工して、保存して終わり、みたいなもの。

**Errオブジェクトまで使うケース**
→ ループ内で大量データを処理するとき。1件のエラーで全体を止めたくないとき。

考えてみてほしい。1万件のデータを処理するマクロで、9,999件目にエラーが出て全部やり直しになったら? エラー処理があれば、その1件だけスキップして残りは正常に完了する。この差は大きい。


実務で使えるテンプレート──コピペしてすぐ使える


私が実際の案件で使っているテンプレートを載せておく。

vb
Sub 業務処理テンプレート()
    ' --- 初期設定 ---
    On Error GoTo 想定外エラー

    Dim startTime As Double
    startTime = Timer

    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual

    Dim lastRow As Long
    lastRow = Cells(Rows.Count, 1).End(xlUp).Row

    Dim errLog As String
    Dim errCount As Long
    Dim i As Long

    ' --- メインループ ---
    For i = 2 To lastRow
        On Error Resume Next

        '=== ここに実際の処理を書く ===
        ' 例: Cells(i, 3).Value = Cells(i, 1).Value * Cells(i, 2).Value
        '================================

        If Err.Number <> 0 Then
            errLog = errLog & "行" & i & ": " & Err.Description & vbCrLf
            errCount = errCount + 1
            Err.Clear
        End If
        On Error GoTo 想定外エラー
    Next i

    ' --- 後処理 ---
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic

    Dim elapsed As Double
    elapsed = Round(Timer - startTime, 1)

    If errCount > 0 Then
        MsgBox "処理完了(" & elapsed & "秒)" & vbCrLf & _
               errCount & "件のエラーあり:" & vbCrLf & errLog, vbExclamation
    Else
        MsgBox "正常に完了しました(" & elapsed & "秒、" & _
               lastRow - 1 & "件処理)", vbInformation
    End If
    Exit Sub

想定外エラー:
    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    MsgBox "想定外のエラーが発生しました" & vbCrLf & _
           "場所: 行" & i & vbCrLf & _
           "Err " & Err.Number & ": " & Err.Description, vbCritical
End Sub
```

このテンプレートには、処理時間の計測も入っている。「このマクロ、何秒で終わるの?」と聞かれたときにサッと答えられる。地味に便利。


やりがちな失敗3つ──私も全部やった


On Error GoTo 0 の書き忘れ


Resume Nextを書いたまま解除し忘れるパターン。後続の処理でバグが出ても気づけない。これ、デバッグが本当に地獄になる。「動いてるのに結果がおかしい」という最悪の状況になる。

Exit Sub の書き忘れ


さっきも書いたけど、本当に多い。正常終了してもエラーメッセージが出る。ユーザーは「毎回エラーが出るんですけど」と混乱する。

Err.Clear の書き忘れ


ループ内でErrオブジェクトをチェックするとき、`Err.Clear` を忘れると前のループのエラー情報が残ったまま次のループに入る。結果、エラーじゃない行もエラー扱いになる。

この3つ、紙に書いてモニターに貼っておくだけでバグが激減する。冗談じゃなく、本当に効く。


エラー処理を入れたら何が変わったか


数字で話すと、私のクライアント案件では:

  • マクロの「突然停止」による業務中断が月4〜5回 → ほぼ0回に(95%減)

  • - エラー発生時の原因調査が平均2時間 → 10分に短縮(エラーログのおかげ)

エラー処理は「めんどくさい追加作業」じゃない。未来の自分を助ける投資だ。

ところが、ここで正直に言うと、エラー処理を入れるのが習慣になるまで3ヶ月くらいかかった。最初は「あとで入れよう」と思って結局入れない、の繰り返し。だからテンプレートを作った。テンプレートがあれば、最初からエラー処理込みで書き始められる。


明日からやること


記事を読んだだけでは何も変わらない。だから、具体的なアクションを1つだけ提案する。

**今動いているマクロの中で、一番よく使うものを1つ選んで、上のテンプレートのエラー処理を追加してみてほしい。**

全部のマクロに一気に入れようとしなくていい。まず1つ。それで「あ、エラーが出てもちゃんと処理が続くじゃん」と実感できたら、自然と他のマクロにも入れたくなるはず。


もっとExcelスキルを磨きたい方へ


エラー処理を入れるだけで、マクロの信頼性は劇的に上がる。「動いたり動かなかったりするマクロ」から「何があっても結果を返すマクロ」に変わる。

有料記事では、今回のテンプレートの応用パターン(ログファイル出力版、メール通知版、リトライ処理付き版)と、実務でよく遭遇するエラー番号の早見表をまとめている。

もし興味があれば覗いてみてほしい。ただ、まずはこの記事のテンプレートを実際に使ってみて、効果を実感してからで全然OK。焦る必要はない。

いいなと思ったら応援しよう!