Contents
この記事でできること
- VBAマクロがエラーで途中停止しなくなる(On Error Resume Next)
- エラーの内容(番号・説明・対象データ)をログシートに自動記録できる(On Error GoTo)
- 「止まらない」と「原因を追跡できる」を両立した実務向けマクロが作れる
対象: Excel 2016以降 / Microsoft 365、Windows 10/11
完成イメージ(Before / After)
Before(エラー処理なし):
- 100件のファイルを処理するマクロを実行
- 38件目でファイル名ミスのエラーが発生
- 「実行時エラー ’53’: ファイルが見つかりません」で停止
- 残り62件は未処理のまま
- 原因を直して1件目からやり直し(処理済み37件も再実行)
After(エラー処理あり):
- 100件のファイルを処理するマクロを実行
- 38件目でエラーが発生 → ログシートに自動記録
- 39件目から処理を継続
- 100件すべて完了後、「処理完了: 99件成功 / 1件エラー」と表示
- ログシートでエラー箇所を確認し、38件目だけ手動で対応
自分も以前、100件のファイルを処理するマクロを作ったことがある。テストでは問題なく動いた。だが本番で実行したら、38件目で止まった。ファイル名が1件だけ全角スペース入りだった。残り62件は未処理。しかも処理済みの37件をもう一度やり直す羽目になった。合計1時間のロス。
On Error GoToでエラーをログに記録し、処理を続行する仕組みにしてからは、100件中1件エラーがあっても残り99件は最後まで走る。翌朝ログを見て、エラーの1件だけ手動で直せばいい。「止まらないマクロ」は、自分だけでなく同僚にも安心して渡せる。
マクロが止まるたびに「VBAは怖い」と思っている人に、この記事で「止まらないマクロ」を体験してほしい。
エラー処理は「保険」。事故が起きてから入るのではなく、最初から組み込むもの。
なお、マクロをボタンに割り当てれば毎回Alt+F8を押す手間がなくなる。方法は マクロをボタン1つで実行する方法 を参照。ファイル処理系マクロを作る前には 指定フォルダのファイルを自動バックアップする方法 でバックアップを取っておくと安心。
実行前の準備
エラー処理の2つの方式を理解する
VBAのエラー処理には大きく2つの方式がある。
| 方式 | 書き方 | 用途 |
|---|---|---|
| **スキップ方式** | `On Error Resume Next` | 1行だけエラーを無視したいとき |
| **ジャンプ方式** | `On Error GoTo ラベル` | エラー内容を記録・分岐したいとき |
この記事では、最小版で「スキップ方式」、実務版で「ジャンプ方式 + エラーログ記録」を紹介する。
Excelをマクロ有効ブック(.xlsm)で保存する
拡張子が .xlsx のままだとマクロが保存できない。
- 「ファイル」→「名前を付けて保存」
- ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
- 保存
手順(コピペ → 実行まで約5分)
VBE(コードを書く画面)を開く
- Excelで
Alt + F11を押す - VBE(Visual Basic Editor)が開く
標準モジュールを挿入する
- VBEのメニュー →「挿入」→「標準モジュール」
- 白い画面(コードウィンドウ)が表示される
コードを貼り付けて実行する
- コードウィンドウに、下のコードをそのままコピペする
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` | 取得したいシート名 | `”集計”` |
コードの流れ
On Error Resume Nextでエラースキップを有効化Set ws = ThisWorkbook.Worksheets(targetSheetName)でシートを取得(存在しなければエラー → スキップされて ws は Nothing のまま)On Error GoTo 0でエラースキップを必ず解除If ws Is Nothingでシートが取得できたかを判定- 取得できなければメッセージを出して終了
重要: 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 + ログ記録を使うようにしている。
'============================================================
' ■ エラー処理(実務版)
' → 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”` |
コードの流れ
- ログシート準備:
ErrorLogシートが存在しなければ自動作成し、ヘッダー行を追加 - 全シートをループ:
For Each ws In ThisWorkbook.Worksheetsで全シートを処理 - エラーハンドリング開始:
On Error GoTo ErrHandlerでエラー発生時にジャンプ先を指定 - 正常処理: A列の値を1.1倍にしてB列に記録(これは例。実務に合わせて書き換える)
- エラー時:
ErrHandlerラベルにジャンプし、Err.Number / Err.Description をログシートに記録 - 次のシートへ:
Resume NextSheetで次のシートの処理に進む - 完了メッセージ: 成功件数とエラー件数を表示
エラーログの記録があれば、翌朝出社して「何件エラーがあったか」「どのシートのどの行か」がすぐ分かる。複数シートの一括処理については 複数シートを一括処理する方法 を参照。
よくある落とし穴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 を入れる方法もあるが、エラーハンドラが複雑になるのは設計の問題。
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では、ファイルパスが違う、シート名が違う、データ型が違うなど、想定外のエラーが頻発する。エラー処理を入れておけば「止まっても原因が分かる」マクロになる。
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での解除を忘れると、全エラーが握りつぶされる- エラー処理は「保険」。マクロを人に渡す前に必ず入れる
関連記事
- 複数Excelファイルを1つに統合 — ファイル統合時にエラー処理を組み合わせると安心
- ExcelファイルをPDFに一括変換 — PDF変換で開けないファイルがあってもスキップ可能
- 古いファイルを自動削除 — 削除処理のエラー(ファイルが開かれている等)を安全に処理
次にやりたくなること
- 指定フォルダのファイルを自動バックアップする方法: エラー処理+バックアップで「壊さない+止まらない」マクロの完成形
- 複数シートを一括処理する方法: エラー処理と組み合わせれば、シート数が増えても安定して動くマクロが作れる
エラー処理を入れたマクロは、安心して人に渡せる。まずは最小版で「止まらないマクロ」を体験してみてほしい。


コメント