【VBA】エラー処理(On Error)で止まらないマクロを作る方法(コピペOK)

VBA
スポンサーリンク
スポンサーリンク
  1. この記事でできること
  2. 完成イメージ(Before / After)
  3. どんな場面で使う?
  4. 実行前の準備
    1. エラー処理の2つの方式を理解する
    2. Excelをマクロ有効ブック(.xlsm)で保存する
  5. 手順(コピペ → 実行まで約5分)
    1. VBE(コードを書く画面)を開く
    2. 標準モジュールを挿入する
    3. コードを貼り付けて実行する
  6. コード(最小版)– On Error Resume Next で単一処理のエラーをスキップ
    1. 書き換えポイント
    2. コードの流れ
  7. コード(実務版)– On Error GoTo + Err.Number + エラーログ記録
    1. 書き換えポイント
    2. コードの流れ
  8. よくある落とし穴5選
    1. 1. On Error Resume Next を解除し忘れて全エラーが無視される
    2. 2. Exit Sub を忘れてエラーハンドラが正常時も実行される
    3. 3. Resume Next の入れすぎでエラーが握りつぶされる
    4. 4. Err.Clear を呼ばずにエラー情報が残ったまま次の処理に進む
    5. 5. エラーハンドラ内でさらにエラーが発生して止まる
    6. VBAのOn Error GoToでエラーハンドラに飛ばないときの対処法
    7. VBAでResume Nextを使ったらエラーが無視されすぎるときの対処法
  9. FAQ
    1. Q1: On Error Resume Next と On Error GoTo はどう使い分ける?
    2. Q2: Err.Number でよく使う番号は?
    3. Q3: エラーログをファイルに出力したい
    4. Q4: マクロを人に渡すとき、エラー処理は必須?
    5. Q5: On Error GoTo -1 は何をするもの?
  10. まとめ
    1. 関連記事
  11. 次にやりたくなること

この記事でできること

「100件処理するマクロが38件目で止まった。残り62件は手作業でやり直し…」 こんな経験はないだろうか。この記事のエラー処理コードを追加すれば、エラーがあっても処理が最後まで走り、原因はログシートに自動記録される。On ErrorとErr.Numberの2つを覚えるだけなので、VBA初心者でもすぐ実装できる。

  • VBAマクロがエラーで途中停止しなくなる(On Error Resume Next)
  • エラーの内容(番号・説明・対象データ)をログシートに自動記録できる(On Error GoTo)
  • 「止まらない」と「原因を追跡できる」を両立した実務向けマクロが作れる

対象: Excel 2016以降 / Microsoft 365、Windows 10/11

完成イメージ(Before / After)

Before(エラー処理なし):

  1. 100件のファイルを処理するマクロを実行
  2. 38件目でファイル名ミスのエラーが発生
  3. 「実行時エラー ’53’: ファイルが見つかりません」で停止
  4. 残り62件は未処理のまま
  5. 原因を直して1件目からやり直し(処理済み37件も再実行)

After(エラー処理あり):

  1. 100件のファイルを処理するマクロを実行
  2. 38件目でエラーが発生 → ログシートに自動記録
  3. 39件目から処理を継続
  4. 100件すべて完了後、「処理完了: 99件成功 / 1件エラー」と表示
  5. ログシートでエラー箇所を確認し、38件目だけ手動で対応

自分も以前、100件のファイルを処理するマクロを作ったことがある。テストでは問題なく動いた。だが本番で実行したら、38件目で止まった。ファイル名が1件だけ全角スペース入りだった。残り62件は未処理。しかも処理済みの37件をもう一度やり直す羽目になった。合計1時間のロス。

On Error GoToでエラーをログに記録し、処理を続行する仕組みにしてからは、100件中1件エラーがあっても残り99件は最後まで走る。翌朝ログを見て、エラーの1件だけ手動で直せばいい。「止まらないマクロ」は、自分だけでなく同僚にも安心して渡せる。

どんな場面で使う?

  • 100件のファイルを処理するマクロで、1件のエラーで全体が止まるのを防ぎたい
  • 同僚に渡すマクロが途中で止まって「壊れた?」と問い合わせが来るのをなくしたい
  • エラーが起きたファイルだけログに記録して、残りは最後まで処理を続けたい
  • Application.ScreenUpdating = False のまま止まって画面が固まる事故を防ぎたい

マクロが途中で止まって、画面更新がオフのまま固まった経験がある。上司の前でフリーズして焦った。Application.ScreenUpdating = False を設定した後にエラーで止まると、画面が真っ白のまま操作不能になる(画面更新の制御については 画面更新・再計算を止めてマクロを高速化する方法 を参照)。On Errorを覚えてからは、エラーが出てもログを吐いて安全に止まるマクロが書けるようになった。

マクロが止まるたびに「VBAは怖い」と思っている人に、この記事で「止まらないマクロ」を体験してほしい。

エラー処理は「保険」。事故が起きてから入るのではなく、最初から組み込むもの。

なお、マクロをボタンに割り当てれば毎回Alt+F8を押す手間がなくなる。方法は マクロをボタン1つで実行する方法 を参照。ファイル処理系マクロを作る前には 指定フォルダのファイルを自動バックアップする方法 でバックアップを取っておくと安心。

実行前の準備

エラー処理の2つの方式を理解する

VBAのエラー処理には大きく2つの方式がある。

方式 書き方 用途
スキップ方式 On Error Resume Next 1行だけエラーを無視したいとき
ジャンプ方式 On Error GoTo ラベル エラー内容を記録・分岐したいとき

この記事では、最小版で「スキップ方式」、実務版で「ジャンプ方式 + エラーログ記録」を紹介する。

Excelをマクロ有効ブック(.xlsm)で保存する

拡張子が .xlsx のままだとマクロが保存できない。

  1. 「ファイル」→「名前を付けて保存」
  2. ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
  3. 保存

手順(コピペ → 実行まで約5分)

VBE(コードを書く画面)を開く

  1. Excelで Alt + F11 を押す
  2. VBE(Visual Basic Editor)が開く

標準モジュールを挿入する

  1. VBEのメニュー →「挿入」→「標準モジュール」
  2. 白い画面(コードウィンドウ)が表示される

コードを貼り付けて実行する

  1. コードウィンドウに、下のコードをそのままコピペする
  2. Alt + F8 → マクロ名を選んで「実行」

ボタンに割り当てれば毎回Alt+F8を押さなくて済む。方法は マクロをボタン1つで実行する方法 を参照。

コード(最小版)– On Error Resume Next で単一処理のエラーをスキップ


'============================================================
' ■ エラー処理(最小版)
'   → On Error Resume Next で1行だけエラーをスキップ
'   → 存在しないシートを安全に取得する例
'============================================================
Sub ErrorHandlingMinimal()

    '--- ★書き換えポイント ---
    Dim targetSheetName As String
    targetSheetName = "集計"   '← 取得したいシート名
    '--- ★ここまで ---

    Dim ws As Worksheet

    '--- エラーを一時的にスキップする
    On Error Resume Next
    Set ws = ThisWorkbook.Worksheets(targetSheetName)
    On Error GoTo 0   '← ★必ず解除する

    '--- エラーが起きたかどうかを判定
    If ws Is Nothing Then
        MsgBox "シート「" & targetSheetName & "」が見つかりません。" & vbCrLf & _
               "シート名を確認してください。", vbExclamation
        Exit Sub
    End If

    '--- シートが見つかった場合の処理
    MsgBox "シート「" & ws.Name & "」を取得しました。" & vbCrLf & _
           "データ範囲: A1:" & ws.Cells(ws.Rows.Count, 1).End(xlUp).Address, vbInformation

End Sub

書き換えポイント

変数 説明 初期値
targetSheetName 取得したいシート名 "集計"

コードの流れ

  1. On Error Resume Next でエラースキップを有効化
  2. Set ws = ThisWorkbook.Worksheets(targetSheetName) でシートを取得(存在しなければエラー → スキップされて ws は Nothing のまま)
  3. On Error GoTo 0 でエラースキップを必ず解除
  4. If ws Is Nothing でシートが取得できたかを判定
  5. 取得できなければメッセージを出して終了

重要: On Error Resume Next の後には必ず On Error GoTo 0 を書いて解除する。解除しないと、以降のすべてのエラーが無視されてしまう。この「解除忘れ」がResume Nextで一番多い事故の原因。

コード(実務版)– On Error GoTo + Err.Number + エラーログ記録

実務では「止まらない」だけでなく「なぜエラーが起きたかを後から追跡できる」ことが重要。エラーの内容をログシートに自動記録する実務版。

自分自身、以前はResume Nextをコード全体に入れて「止まらないマクロ」を作った気になっていた。だが翌月の集計で数値が合わない。調べてみると、Resume Nextでエラーが握りつぶされて、10件ほどデータが処理されていなかった。原因調査に丸1日かかった。それ以来、Resume Nextは「1行だけ」に限定し、実務では必ずOn Error GoTo + ログ記録を使うようにしている。

エラーログを仕込んでおけば、ファイル統合(複数Excelファイルを1つに統合)やPDF一括変換(ExcelファイルをPDFに一括変換)のようにファイル数が多い処理でも安心して実行できる。処理の進捗をステータスバーに表示する方法は ステータスバーで処理の進捗を表示する方法 も参考にしてほしい。


'============================================================
' ■ エラー処理(実務版)
'   → On Error GoTo でエラーをキャッチし、ログシートに自動記録
'   → 複数シートを一括処理し、エラーがあっても最後まで実行
'============================================================
Sub ErrorHandlingAdvanced()

    '--- ★書き換えポイント ---
    Dim logSheetName As String
    logSheetName = "ErrorLog"   '← エラーログを記録するシート名
    '--- ★ここまで ---

    '--- ログシートを準備(なければ自動作成)
    Dim wsLog As Worksheet
    On Error Resume Next
    Set wsLog = ThisWorkbook.Worksheets(logSheetName)
    On Error GoTo 0

    If wsLog Is Nothing Then
        Set wsLog = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
        wsLog.Name = logSheetName
        '--- ヘッダー行を作成
        wsLog.Range("A1").Value = "日時"
        wsLog.Range("B1").Value = "マクロ名"
        wsLog.Range("C1").Value = "エラー番号"
        wsLog.Range("D1").Value = "エラー内容"
        wsLog.Range("E1").Value = "対象データ"
        wsLog.Rows(1).Font.Bold = True
    End If

    '--- 処理カウンター
    Dim successCount As Long
    Dim errorCount As Long
    successCount = 0
    errorCount = 0

    '--- 全シートを一括処理(ErrorLogシートは除く)
    Dim ws As Worksheet
    For Each ws In ThisWorkbook.Worksheets

        '--- ログシート自身はスキップ
        If ws.Name = logSheetName Then GoTo NextSheet

        '--- ★ここからエラーハンドリング開始 ---
        On Error GoTo ErrHandler

        '--- シートのA列最終行を取得
        Dim lastRow As Long
        lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row

        '--- B列に「処理済み」スタンプを押す(例)
        Dim i As Long
        For i = 2 To lastRow
            '--- A列の値を数値に変換してB列に記録
            ws.Cells(i, 2).Value = CDbl(ws.Cells(i, 1).Value) * 1.1
        Next i

        successCount = successCount + 1
        GoTo NextSheet

ErrHandler:
        '--- エラー情報をログシートに記録
        Dim logRow As Long
        logRow = wsLog.Cells(wsLog.Rows.Count, 1).End(xlUp).Row + 1

        wsLog.Cells(logRow, 1).Value = Now                  '日時
        wsLog.Cells(logRow, 2).Value = "ErrorHandlingAdvanced" '  マクロ名
        wsLog.Cells(logRow, 3).Value = Err.Number            'エラー番号
        wsLog.Cells(logRow, 4).Value = Err.Description       'エラー内容
        wsLog.Cells(logRow, 5).Value = "シート: " & ws.Name & " / 行: " & i  '対象データ

        errorCount = errorCount + 1
        Err.Clear
        Resume NextSheet   '← 次のシートに進む

NextSheet:
        On Error GoTo 0   '← エラー処理をリセット
    Next ws

    '--- 完了メッセージ
    Dim msg As String
    msg = "処理完了" & vbCrLf & _
          "成功: " & successCount & " シート" & vbCrLf & _
          "エラー: " & errorCount & " シート"

    If errorCount > 0 Then
        msg = msg & vbCrLf & vbCrLf & _
              "エラー詳細は「" & logSheetName & "」シートを確認してください。"
    End If

    MsgBox msg, vbInformation

End Sub

書き換えポイント

変数 説明 初期値
logSheetName エラーログを記録するシート名 "ErrorLog"

コードの流れ

  1. ログシート準備: ErrorLog シートが存在しなければ自動作成し、ヘッダー行を追加
  2. 全シートをループ: For Each ws In ThisWorkbook.Worksheets で全シートを処理
  3. エラーハンドリング開始: On Error GoTo ErrHandler でエラー発生時にジャンプ先を指定
  4. 正常処理: A列の値を1.1倍にしてB列に記録(これは例。実務に合わせて書き換える)
  5. エラー時: ErrHandler ラベルにジャンプし、Err.Number / Err.Description をログシートに記録
  6. 次のシートへ: Resume NextSheet で次のシートの処理に進む
  7. 完了メッセージ: 成功件数とエラー件数を表示

エラーログの記録があれば、翌朝出社して「何件エラーがあったか」「どのシートのどの行か」がすぐ分かる。複数シートの一括処理については 複数シートを一括処理する方法 を参照。

よくある落とし穴5選

1. On Error Resume Next を解除し忘れて全エラーが無視される

原因: On Error Resume Next の後に On Error GoTo 0 を書き忘れると、以降のコード全体でエラーが無視される。

自分もこれでハマった。Resume Nextを1行だけのつもりで書いたが、GoTo 0を入れ忘れた。その結果、シート名のスペルミスも、セル範囲の指定ミスも、全部スルーされた。データがおかしいことに気づいたのは3日後だった。

対策: On Error Resume Next を書いたら、すぐ次の行か数行後に On Error GoTo 0 を書く。この2つは必ずセットで使う。

2. Exit Sub を忘れてエラーハンドラが正常時も実行される

原因: On Error GoTo ErrHandler の構文で、エラーハンドラのラベル(ErrHandler:)の手前に Exit Sub がないと、正常終了時もエラーハンドラのコードが実行されてしまう。

対策: 以下の構文を必ず守る。


Sub Sample()
    On Error GoTo ErrHandler
    ' 正常処理
    Exit Sub          '← ★これが必須
ErrHandler:
    ' エラー処理
End Sub

3. Resume Next の入れすぎでエラーが握りつぶされる

原因: コード全体を On Error Resume Next で囲むと、本来検知すべきエラーもすべてスキップされる。データが欠損しても気づけない。

自分の失敗談だが、以前100件のデータ処理でコード冒頭に On Error Resume Next を書いた。止まらなくなったのは良かったが、翌月の集計で数値が合わない。調べたら10件分のデータが処理されていなかった。Resume Nextでエラーがスキップされ、データが書き込まれていなかったのが原因。原因調査に丸1日かかった。

対策: Resume Nextは「1行だけ」に限定する。複数行の処理には On Error GoTo を使い、エラーをログに記録する。

4. Err.Clear を呼ばずにエラー情報が残ったまま次の処理に進む

原因: On Error Resume Next でエラーをスキップした後、Err.Number を確認せずに次の処理に進むと、前のエラー情報が残ったままになる。

対策: エラーチェック後は Err.Clear で明示的にクリアする。または On Error GoTo 0 でリセットする(GoTo 0 はErr情報もクリアされる)。

5. エラーハンドラ内でさらにエラーが発生して止まる

原因: On Error GoTo ErrHandler のエラーハンドラ内でエラーが発生すると、二重エラーで強制停止する。たとえば、ログシートへの書き込み自体がエラーになるケース。

自分もこれを経験した。ログシートが保護されていたのを忘れていて、エラーハンドラ内でさらにエラーが発生。「エラー処理を入れたのにエラーで止まる」という皮肉な状況になった。

対策: エラーハンドラ内の処理は極力シンプルにする。ログ書き込みの前に On Error Resume Next を入れる方法もあるが、エラーハンドラが複雑になるのは設計の問題。エラーの原因を効率よく特定するには VBAのデバッグ技術を使いこなす方法 のブレークポイントやウォッチ式も活用してほしい。

VBAのOn Error GoToでエラーハンドラに飛ばないときの対処法

「On Error GoToを書いたのにエラーでマクロが止まる」という場合、原因はエラーハンドラの中で再びエラーが発生する「二重エラー」だ。エラーハンドラ内の処理はログ書き込み程度に留め、複雑な処理は入れないこと。ログシートが保護されていないかも確認するとよい。

VBAでResume Nextを使ったらエラーが無視されすぎるときの対処法

「処理は最後まで走るが結果がおかしい」という場合、原因は On Error Resume Next がエラーを黙って無視し続けていることだ。Resume Nextは1行のチェック処理(ファイル存在確認など)だけに使い、すぐに On Error GoTo 0 でリセットすること。長い処理には On Error GoTo ラベル 方式を使うのが安全だ。

FAQ

Q1: On Error Resume Next と On Error GoTo はどう使い分ける?

場面 方式 理由
ファイル・シートの存在確認(1行) Resume Next 結果をIf文で判定できる
ループ内の複数行処理 GoTo ラベル エラー内容を記録して続行できる
処理全体のセーフティネット GoTo ラベル 想定外エラーをキャッチできる

Q2: Err.Number でよく使う番号は?

番号 説明 よくある原因
9 インデックスが有効範囲にない 存在しないシート名
13 型が一致しない 文字列を数値変換
53 ファイルが見つからない パスの間違い
70 書き込みできない ファイルが開かれている
1004 アプリケーション定義エラー シート保護、範囲外

Q3: エラーログをファイルに出力したい

シートではなくテキストファイルに出力することも可能。


Dim f As Integer
f = FreeFile
Open "C:\log\error_log.txt" For Append As #f
Print #f, Now & vbTab & Err.Number & vbTab & Err.Description
Close #f

ファイル出力の基本は フォルダ内ファイル一覧を自動取得 でDir関数を使ったファイル操作を解説している。

Q4: マクロを人に渡すとき、エラー処理は必須?

必須ではないが、強く推奨する。エラー処理なしのマクロは、自分の環境でしかテストされていない。別の人のPCでは、ファイルパスが違う、シート名が違う、データ型が違うなど、想定外のエラーが頻発する。エラー処理を入れておけば「止まっても原因が分かる」マクロになる。渡す前に MsgBoxで確認ダイアログを出して処理を分岐する方法 で安全確認のダイアログを付けておくとさらに安心。

Q5: On Error GoTo -1 は何をするもの?

On Error GoTo -1 は、エラー処理状態をリセットする。通常は On Error GoTo 0 で十分だが、エラーハンドラ内でさらに別の On Error GoTo を使いたい場合に必要になる。初心者のうちは On Error GoTo 0 だけ覚えておけば問題ない。

まとめ

  • On Error Resume Next は「1行だけ」のエラースキップに使う(最小版)
  • On Error GoTo ラベル + Err.Number + ログ記録で「止まらない+原因追跡」を両立(実務版)
  • On Error GoTo 0 での解除を忘れると、全エラーが握りつぶされる
  • エラー処理は「保険」。マクロを人に渡す前に必ず入れる

関連記事

  • エラー処理の応用パターン(リトライ・ログ・通知)を実装する方法 — リトライや通知などエラー処理の発展形
  • VBAのデバッグ技術を使いこなす方法 — エラーの原因を素早く特定するデバッグ技術
  • 複数Excelファイルを1つに統合 — ファイル統合時にエラー処理を組み合わせると安心
  • ExcelファイルをPDFに一括変換 — PDF変換で開けないファイルがあってもスキップ可能
  • 古いファイルを自動削除 — 削除処理のエラー(ファイルが開かれている等)を安全に処理

次にやりたくなること

  • エラー処理の応用パターン(リトライ・ログ・通知)を実装する方法 — リトライ処理やメール通知など、エラー処理をさらに実務レベルに引き上げたい場合に
  • VBAのデバッグ技術を使いこなす方法 — エラーの原因特定を効率化するブレークポイント・ステップ実行・ウォッチ式の使い方
  • 複数Excelファイルを1つに統合 — ファイル統合にエラー処理を組み合わせると、開けないファイルがあってもスキップして最後まで完了する
  • ExcelファイルをPDFに一括変換 — PDF変換でもエラー処理は必須。壊れたファイルをスキップして残りを処理できる
  • ステータスバーで処理の進捗を表示する方法 — エラー処理+進捗表示で「止まらない+今どこまで進んだか分かる」マクロの完成形

エラー処理を入れたマクロは、安心して人に渡せる。まずは最小版で「止まらないマクロ」を体験してみてほしい。

コメント

タイトルとURLをコピーしました