- 技術 💻
VBA実行時エラー一覧|1004・9・13・91の原因と対処
VBAの実行時エラーとは、マクロを実行している途中で処理を続けられなくなったときに、番号とメッセージつきで表示されるエラーです。 番号ごとに原因の型が決まっているので、番号から原因と直し方を引けるようにしておくと、調べる時間をぐっと短くできます。
この記事は、エラー番号から引くためのリファレンスです。前半で頻出23番号の早見表と、特によく出る10番号の「発生するコード」と「修正後のコード」を対で示します。後半では、On Error と Resume の各形式の違い、Err オブジェクトを使ったエラー処理の定型とログ出力をまとめます。
確認環境:エラー番号とメッセージ、原因と解決策、On Error・Resume・Err オブジェクトの仕様、コードで使っているステートメント・関数・メソッドの構文は、2026年10月5日に Microsoft Learn の VBA リファレンス(日本語版)の各ページを開いて確認した内容です。コードはその構文に沿って書いたもので、Excel の画面出力は掲載していません。
VBA実行時エラーの番号別早見表(頻出23番号)
メッセージは Microsoft Learn「トラップできるエラー」の一覧にある日本語の表記です。
| 番号 | メッセージ | よくある原因 | 直し方 |
|---|---|---|---|
| 5 | プロシージャ呼び出しが正しくありません | 関数に渡した引数が、許可される範囲を超えている | 関数のリファレンスで引数の範囲を確かめ、範囲内の値を渡す |
| 6 | オーバーフローしました | 代入・計算・型変換の結果が、変数の型で扱える範囲を超えた | より広い範囲を持てる型(Long、Double など)にする。計算式は CLng で変換してから掛ける |
| 7 | メモリが不足しています | 開いているアプリケーションやドキュメントが多い。モジュールやプロシージャが大きすぎる | 不要なものを閉じる。モジュールやプロシージャを小さく分ける |
| 9 | インデックスが有効範囲にありません | 存在しない配列の要素や、コレクションに無いメンバー(シート名など)を指定した | LBound・UBound で範囲を確かめる。コレクションは For Each でたどる |
| 11 | 0 で除算しました | 割る数として使っている式の値がゼロ | 変数名のつづりを確かめる。割る前にゼロかどうかを判定する |
| 13 | 型が一致しません | 数値型の変数に、数値として読めない文字列を入れた。値が必要な場所にオブジェクトを渡した | 互換性のある型どうしで代入する。IsNumeric で確かめてから変換する |
| 20 | エラーが発生していないときに Resume を実行することはできません | エラー処理ルーチンの外で Resume が実行された | ラベルの直前に Exit Sub を置き、通常の流れでエラー処理ルーチンに入らないようにする |
| 28 | スタック領域が不足しています | プロシージャの入れ子が深い。再帰呼び出しが終わらない。イベントが連鎖している | 再帰の終了条件を確かめる。呼び出し履歴でイベントの連鎖を調べる |
| 52 | ファイル名または番号が正しくありません | Open していない(または閉じた)ファイル番号を使った。ファイル名に使えない文字がある | 先に Open で開く。ファイル番号は 1〜511 の範囲にする。ファイル名を見直す |
| 53 | ファイルが見つかりません | Kill・Name・Open などが、存在しないファイルを指している |
ファイル名とパスのつづりを確かめる。Dir で有無を調べてから操作する |
| 55 | ファイルは既に開かれています | 開いているファイルを別のモードで Open した。開いているファイルに Kill や Name を実行した |
先に Close で閉じてから操作する |
| 58 | 既に同名のファイルが存在しています | Name で指定した新しいファイル名が、既存のファイルと同じ |
別の名前を指定する。または既存のファイルを先に削除する |
| 62 | ファイルにこれ以上データがありません | Input # や Line Input # で、読み終えたファイルや空のファイルを読もうとした |
読む直前に EOF でファイルの終わりを確かめる |
| 70 | アクセス許可が拒否されました | 書き込み禁止のファイルを Output や Append で開いた。別のプロセスがロックしているファイルに書こうとした | Input で開く、書き込み禁止の属性を変える、ほかのプロセスが解放するのを待つ |
| 75 | パス名/ファイル名が無効です | パスの形式が正しくない。読み取り専用ファイルを上書き・出力モードで開こうとした | ドライブ名から始まるパスか、正しい相対パスにする。別名で保存する |
| 76 | パスが見つかりません | Open・MkDir・ChDir・RmDir などで、指定したパスが見つからない |
ドライブとフォルダーの指定を見直す |
| 91 | オブジェクト変数または With ブロック変数が設定されていません | Set で代入していない、または Nothing になっているオブジェクト変数を使った |
Set で有効なオブジェクトを代入する。使う前に Nothing かどうかを確かめる |
| 94 | Null の使い方が正しくありません | Null が入った Variant を、有効な値が必要な場所で使った | 使う前に Null かどうかを確かめる。初期値を入れておく |
| 424 | オブジェクトが必要です | オブジェクト名のつづり違い。Set を付けずにオブジェクトを代入した |
つづりを確かめる。オブジェクトの代入には Set を付ける |
| 438 | オブジェクトは、このプロパティまたはメソッドをサポートしていません | そのオブジェクトに無いプロパティやメソッドを指定した | オブジェクトのリファレンスで、プロパティ名・メソッド名のつづりを確かめる |
| 450 | 引数の数が一致していません。または無効なプロパティを指定しています | 呼び出しの引数の数が宣言と合っていない。読み取り専用プロパティに値を入れた | 宣言と引数リストを見比べる |
| 457 | このキーは既にこのコレクションの要素に割り当てられています | コレクションの Add で、すでに使われているキーを指定した |
重複しないキーを使う |
| 1004 | アプリケーション定義またはオブジェクト定義のエラーです | Excel など VBA の外側で起きたエラーが、VBA の番号に対応づけられずに伝わってきた | エラーが出た行で操作しているオブジェクト(セル範囲・シート・ブック)の指定を見直す |
番号がわかったら、まず「どの行で止まったか」を確かめます。 エラーのダイアログで「デバッグ」を押すと、止まった行が黄色で示されます。その行に出てくる変数とオブジェクトを、上の表の原因と照らし合わせるのが近道です。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「VBA実行時エラー一覧|1004・9・13・91の原因と対処」
よく出る10番号:発生するコードと修正後のコード
以降のコードは、標準モジュールに貼る前提です。シート名「注文」は架空の例です。
実行時エラー 1004:アプリケーション定義またはオブジェクト定義のエラー
Microsoft Learn では、このメッセージについて「ほかのアプリケーション(Microsoft Excel など)のオブジェクトにアクセスしたときに、VBA のエラーに対応づけられないエラーがプログラムに伝わることがある」と説明されています。つまり、Excel のオブジェクトに対する指定そのものを見直す番号です。代表例が、存在しないセル番地です。
発生するコード:
Sub Sample1004_Before()
Dim r As Long
r = 0
' 行番号 0 のセルは存在しないので、ここで 1004 になる
Worksheets("注文").Range("A" & r).Value = "見出し"
End Sub
修正後のコード:
Sub Sample1004_After()
Dim r As Long
r = 0
If r < 1 Then
MsgBox "行番号が 1 未満です: " & r
Exit Sub
End If
Worksheets("注文").Range("A" & r).Value = "見出し"
End Sub
1004 が出たときに確かめる点です。
| 確かめる点 | 見るところ |
|---|---|
| セル番地の文字列が正しいか | "A" & r のように組み立てている場合は、変数の中身 |
| 対象のシートが意図したものか | Worksheets("注文").Range(...) のようにシートを明示しているか |
| どのアプリケーションが出したエラーか | Err.Source の値(Microsoft Learn で、発生元の確認方法として紹介) |
実行時エラー 9:インデックスが有効範囲にありません
配列の範囲外の要素や、コレクションに無い名前を指定したときの番号です。Excel では、存在しないシート名の指定が典型です。
発生するコード:
Sub Sample9_Before()
Dim items(1 To 3) As String
' 「集計」という名前のシートが無いと、ここで 9 になる
Worksheets("集計").Range("A1").Value = "合計"
' 要素は 1〜3 なので、4 を指定すると 9 になる
items(4) = "ノート"
End Sub
修正後のコード:
Sub Sample9_After()
Dim items(1 To 3) As String
Dim ws As Object
Dim found As Boolean
Dim i As Long
' コレクションは For Each でたどって有無を確かめる
For Each ws In Worksheets
If ws.Name = "集計" Then found = True
Next ws
If found Then
Worksheets("集計").Range("A1").Value = "合計"
Else
MsgBox "「集計」シートがありません。"
End If
' 配列は LBound と UBound の間だけを使う
For i = LBound(items) To UBound(items)
items(i) = "品名" & i
Next i
End Sub
Microsoft Learn には、Dim MyArray() As Integer のように要素数を指定せずに宣言した配列へ、そのまま MyArray(8) = 234 と代入した場合もこの番号になる、と書かれています。Dim か ReDim で要素数を決めてから使います。
実行時エラー 13:型が一致しません
数値型の変数に、数値として読めない文字列を入れようとしたときの番号です。セルに「未定」のような文字が入っている表で起きやすくなります。
発生するコード:
Sub Sample13_Before()
Dim amount As Long
' A2 に「未定」のような文字が入っていると、ここで 13 になる
amount = Worksheets("注文").Range("A2").Value
MsgBox amount * 2
End Sub
修正後のコード:
Sub Sample13_After()
Dim amount As Long
Dim v As Variant
v = Worksheets("注文").Range("A2").Value
If IsNumeric(v) Then
amount = CLng(v)
MsgBox amount * 2
Else
MsgBox "A2 が数値ではありません: " & v
End If
End Sub
IsNumeric は、式が数値として評価できるときに True を返す関数です。セルの値はいったん Variant で受け、確かめてから型を変換すると、この番号を避けられます。
実行時エラー 91:オブジェクト変数または With ブロック変数が設定されていません
オブジェクト変数に有効なオブジェクトが入っていない(Nothing の)状態で、プロパティやメソッドを使ったときの番号です。Range.Find は、一致するデータが見つからなかった場合に Nothing を返すので、検索結果をそのまま使うコードでよく起きます。
発生するコード:
Sub Sample91_Before()
Dim hit As Range
Set hit = Worksheets("注文").Range("A:A").Find(What:="モニター")
' 見つからないと hit は Nothing なので、ここで 91 になる
MsgBox hit.Row
End Sub
修正後のコード:
Sub Sample91_After()
Dim hit As Range
Set hit = Worksheets("注文").Range("A:A").Find(What:="モニター")
If hit Is Nothing Then
MsgBox "「モニター」は見つかりませんでした。"
Else
MsgBox hit.Row
End If
End Sub
Dim で宣言しただけで Set していないオブジェクト変数も Nothing です。オブジェクト変数は「Set したか」「Nothing ではないか」の2点を確かめます。
実行時エラー 424:オブジェクトが必要です
オブジェクトではないものに対して、プロパティやメソッドを使おうとしたときの番号です。変数名のつづり違いと、Set の付け忘れが代表的な原因です。
発生するコード:
' モジュールの先頭に Option Explicit が無い場合
Sub Sample424_Before()
Dim ws As Worksheet
Set ws = Worksheets("注文")
' wss はつづり違い。宣言のない別の変数として扱われ、ここで 424 になる
wss.Range("A1").Value = "見出し"
End Sub
修正後のコード:
Option Explicit
Sub Sample424_After()
Dim ws As Worksheet
Set ws = Worksheets("注文")
ws.Range("A1").Value = "見出し"
End Sub
モジュールの先頭に Option Explicit を書いておくと、宣言していない変数名は実行前のコンパイルの段階で知らせてもらえます。
Set の付け忘れについては、Microsoft Learn に次の対の例が載っています。
' 発生するコード
Dim RetVal ' Implicitly a Variant.
RetVal = CreateObject("Excel.Application")
RetVal.Visible = True ' Error occurs here.
' 修正後のコード
Dim RetVal As Object
Set RetVal = CreateObject("Excel.Application")
RetVal.Visible = True
実行時エラー 438:オブジェクトは、このプロパティまたはメソッドをサポートしていません
オブジェクト自体は有効でも、そのオブジェクトに無いプロパティやメソッドを指定したときの番号です。
発生するコード:
Sub Sample438_Before()
' ワークシートに Value プロパティは無いので、ここで 438 になる
Worksheets("注文").Value = "見出し"
End Sub
修正後のコード:
Sub Sample438_After()
' 値を持つのはセル範囲(Range)
Worksheets("注文").Range("A1").Value = "見出し"
End Sub
424 との違いは次のとおりです。
| 番号 | 対象そのもの | プロパティ・メソッド | 見直す場所 |
|---|---|---|---|
| 424 | オブジェクトではない | ― | ドットの左側(変数名、Set の有無) |
| 438 | 有効なオブジェクト | そのオブジェクトに無い | ドットの右側(プロパティ名・メソッド名) |
実行時エラー 6:オーバーフローしました
計算や代入の結果が、型の扱える範囲を超えたときの番号です。Microsoft Learn には、代入先が Long でも、計算に使う数値が整数として扱われて途中の結果があふれる例が載っています。
発生するコード(Microsoft Learn の例):
Dim x As Long
x = 2000 * 365 ' Error: Overflow
修正後のコード(Microsoft Learn の例):
Dim x As Long
x = CLng(2000) * 365
行番号や件数を入れる変数は、最初から Long で宣言しておくと安心です。
Sub Sample6_After()
Dim rowCount As Long ' Integer ではなく Long にする
rowCount = 40000
MsgBox rowCount
End Sub
実行時エラー 11:0 で除算しました
割る数がゼロのときの番号です。Microsoft Learn では、変数名のつづり違いによってゼロで初期化された別の変数が使われていないか、も確認点に挙げられています。
発生するコード:
Sub Sample11_Before()
Dim total As Double
Dim cnt As Long
total = 12000
cnt = 0
' cnt が 0 なので、ここで 11 になる
MsgBox total / cnt
End Sub
修正後のコード:
Sub Sample11_After()
Dim total As Double
Dim cnt As Long
total = 12000
cnt = 0
If cnt = 0 Then
MsgBox "件数が 0 のため、平均は計算しません。"
Else
MsgBox total / cnt
End If
End Sub
実行時エラー 53:ファイルが見つかりません
Kill・Name・Open などが、存在しないファイルを指しているときの番号です。
発生するコード:
Sub Sample53_Before()
' ファイルが無いと、ここで 53 になる
Kill "C:\work\temp.csv"
End Sub
修正後のコード:
Sub Sample53_After()
Dim filePath As String
filePath = "C:\work\temp.csv"
' Dir は、見つからないとき長さ 0 の文字列を返す
If Dir(filePath) <> "" Then
Kill filePath
Else
MsgBox "ファイルがありません: " & filePath
End If
End Sub
フォルダーごと見つからない場合は、76(パスが見つかりません)になります。
実行時エラー 70:アクセス許可が拒否されました
書き込み禁止のファイルを Output や Append で開こうとしたとき、または別のプロセスがロックしているファイルに書こうとしたときの番号です。事前の判定だけでは避けにくいので、エラー処理で受けて案内する形にします。
発生するコード:
Sub Sample70_Before()
Dim fileNo As Integer
fileNo = FreeFile
' 書き込み禁止のファイルや、ほかで開かれているファイルだと、ここで 70 になる
Open "C:\work\report.txt" For Append As #fileNo
Print #fileNo, "完了"
Close #fileNo
End Sub
修正後のコード:
Sub Sample70_After()
Dim fileNo As Integer
On Error GoTo ErrHandler
fileNo = FreeFile
Open "C:\work\report.txt" For Append As #fileNo
Print #fileNo, "完了"
Close #fileNo
Exit Sub
ErrHandler:
Select Case Err.Number
Case 70
MsgBox "ファイルに書き込めません。読み取り専用になっていないか、ほかで開かれていないかを確かめてください。"
Case Else
MsgBox "番号: " & Err.Number & " " & Err.Description
End Select
End Sub
読むだけでよい場合は、For Input で開けばこの番号を避けられます(Microsoft Learn の解決策)。
On Errorの3形式の違い
On Error は、エラーが起きたときの進み先を決めるステートメントです。Microsoft Learn には、On Error を使わない場合、発生する実行時エラーはすべて致命的となり、エラーメッセージが表示されて実行が停止する、と書かれています。
| 形式 | 動き | 使いどころ |
|---|---|---|
On Error GoTo ラベル |
実行時エラーが起きると、指定した行ラベル(または行番号)のエラー処理ルーチンへ進む。ラベルは同じプロシージャ内に置く | 基本形。後始末とメッセージ表示をまとめる |
On Error Resume Next |
エラーが起きたステートメントの直後のステートメントから実行を続ける | 「あるかどうか試す」短い区間。直後に Err.Number を確かめる |
On Error GoTo 0 |
現在のプロシージャで有効になっているエラー処理を無効にする | Resume Next の区間を終えるとき |
On Error GoTo ラベルの基本形
Sub BasicHandler()
On Error GoTo ErrHandler
' ここに本体の処理を書く
Worksheets("注文").Range("A1").Value = "見出し"
Exit Sub ' 正常に終わったときは、ここで抜ける
ErrHandler:
MsgBox "番号: " & Err.Number & " " & Err.Description
End Sub
ラベルの直前に Exit Sub(関数なら Exit Function)を置くのが決まりです。置かないと、エラーが起きていないときにもエラー処理ルーチンの行が実行されます。
On Error Resume Next は短い区間だけで使う
Function SheetExists(ByVal sheetName As String) As Boolean
Dim ws As Object
On Error Resume Next ' ここから「試す」区間
Set ws = ThisWorkbook.Worksheets(sheetName)
On Error GoTo 0 ' 区間を終える
SheetExists = Not ws Is Nothing
End Function
On Error Resume Next を書いたままにすると、そのあとのエラーもすべて素通りして、どこで問題が起きたかを追いにくくなります。試したい1〜2行を挟んで、すぐ On Error GoTo 0 で閉じる形にします。
知っておきたい On Error の決まり
Microsoft Learn の On Error ステートメントのページに書かれている内容です。
| 場面 | 動き |
|---|---|
| プロシージャが終了したとき | On Error GoTo 0 を書いていなくても、エラー処理は自動的に無効になる |
| 呼び出し先のプロシージャでエラーが起き、そこにエラー処理が無いとき | 呼び出し元に有効なエラー処理があれば、それが使われる |
| エラー処理ルーチンの実行中に、さらにエラーが起きたとき | そのプロシージャのエラー処理では受けられず、呼び出し元へ制御が渡る |
On Error Resume Next のあとで別のプロシージャを呼んだとき |
呼び出し先では効かない。呼び出し先でも必要なら、そこで改めて書く |
Resumeの3形式の違い
Resume は、エラー処理ルーチンの中から本体の処理へ戻るためのステートメントです。On Error Resume Next と名前が似ていますが、役割が違います。
| 形式 | 戻る場所 | 使いどころ |
|---|---|---|
Resume(Resume 0) |
エラーが起きたステートメント。同じ行をもう一度実行する | 原因をエラー処理ルーチンの中で取り除けるとき(開いていたファイルを閉じる、など) |
Resume Next |
エラーが起きたステートメントの直後のステートメント | その行を飛ばして先へ進めてよいとき |
Resume ラベル |
指定した行ラベル(または行番号)。同じプロシージャ内に置く | 後始末の処理へ進めて終わりたいとき |
呼び出し先のプロシージャで起きたエラーを呼び出し元で受けた場合、Resume は「呼び出しを行ったステートメント」から、Resume Next は「その直後のステートメント」から再開します。
エラー処理ルーチン以外の場所で Resume を実行するとエラーになります(番号 20)。また、Resume は原因を取り除かないまま使うと同じ行でまたエラーになり、処理が繰り返されます。 再試行の回数に上限を付けておくと安心です。
Sub ResumeWithRetry()
Dim fileNo As Integer
Dim retryCount As Long
On Error GoTo ErrHandler
fileNo = FreeFile
Open "C:\work\report.txt" For Append As #fileNo
Print #fileNo, "完了"
Close #fileNo
Exit Sub
ErrHandler:
If Err.Number = 70 And retryCount < 3 Then
retryCount = retryCount + 1
MsgBox "ファイルを閉じてから OK を押してください。(" & retryCount & " 回目)"
Resume ' Open の行をもう一度実行する
End If
MsgBox "番号: " & Err.Number & " " & Err.Description
End Sub
On Error と Resume の対応
| やりたいこと | エラーの受け方 | 戻り方 |
|---|---|---|
| エラーをまとめて受け、メッセージを出して終わる | On Error GoTo ラベル |
戻らずに終了(End Sub へ進む) |
| 後始末を必ず通してから終わる | On Error GoTo ラベル |
Resume 後始末のラベル |
| 原因を取り除いて同じ行をやり直す | On Error GoTo ラベル |
Resume |
| その行だけ飛ばして続ける | On Error GoTo ラベル |
Resume Next |
| 試して、結果を自分で判定する | On Error Resume Next |
Err.Number を確かめ、On Error GoTo 0 で閉じる |
Errオブジェクトの使い方(Number・Description・Raise)
Err は、実行時エラーの情報を持つ組み込みのオブジェクトです。宣言や生成をせずにそのまま使えます。
| メンバー | 種類 | 内容 |
|---|---|---|
Err.Number |
プロパティ | エラー番号(既定のプロパティ)。エラーが無いときは 0 |
Err.Description |
プロパティ | エラーの説明文 |
Err.Source |
プロパティ | エラーの発生元 |
Err.HelpFile・Err.HelpContext |
プロパティ | ヘルプファイルのパスとトピックの番号 |
Err.Clear |
メソッド | Err の内容を明示的にリセットする |
Err.Raise |
メソッド | 実行時エラーを発生させる |
Err の内容がリセットされるタイミング
Microsoft Learn によると、Err のプロパティは、Exit Sub・Exit Function・Exit Property・Resume Next・エラー処理ルーチン内の Resume のあとで、ゼロまたは長さ 0 の文字列にリセットされます。
そのため、エラー処理ルーチンに入ったら、最初に番号と説明を変数へ写しておくと、あとの処理で値が変わる心配がなくなります。次の定型でもこの形にしています。
Err.Raise で独自のエラーを発生させる
構文は次のとおりです。number 以外は省略できます。
Err.Raise number, [source], [description], [helpfile], [helpcontext]
Microsoft Learn には、番号の範囲について次の説明があります。
| 範囲 | 用途 |
|---|---|
| 0〜512 | システムエラー用に予約 |
| 513〜65535 | ユーザー定義のエラーに使える |
| クラスモジュール内 | vbObjectError に自分のエラー番号を足した値を使う |
入力の確認で、独自のエラーを発生させる例です。
Option Explicit
Public Const ERR_NO_DATA As Long = vbObjectError + 513
Sub CheckInput()
If Worksheets("注文").Range("A2").Value = "" Then
Err.Raise Number:=ERR_NO_DATA, _
Source:="CheckInput", _
Description:="A2 が空です。データを貼り付けてから実行してください。"
End If
End Sub
呼び出し元では、Err.Number で独自の番号かどうかを見分けられます。
Sub RunCheck()
On Error GoTo ErrHandler
CheckInput
MsgBox "入力の確認が終わりました。"
Exit Sub
ErrHandler:
Select Case Err.Number
Case ERR_NO_DATA
MsgBox Err.Description
Case Else
MsgBox "番号: " & Err.Number & " " & Err.Description
End Select
End Sub
エラー処理の定型とログ出力
ここまでの要素を1つにまとめた、コピーして使える形です。「後始末を必ず通す」「Err の内容を先に変数へ写す」「ログに残す」の3点を入れています。
本体側の定型
Option Explicit
Public Sub RunMonthlyReport()
Const PROC_NAME As String = "RunMonthlyReport"
Dim errNo As Long
Dim errMsg As String
Dim errSrc As String
On Error GoTo ErrHandler
Application.ScreenUpdating = False
' ここに本体の処理を書く
Worksheets("注文").Range("A1").Value = "見出し"
CleanUp:
' 正常時もエラー時も必ず通る後始末
Application.ScreenUpdating = True
Exit Sub
ErrHandler:
' 1. Err の内容を先に変数へ写す
errNo = Err.Number
errMsg = Err.Description
errSrc = Err.Source
' 2. ログに残す
WriteErrorLog PROC_NAME, errNo, errMsg, errSrc
' 3. 利用者に知らせる
MsgBox "処理を中断しました。" & vbCrLf & _
"番号: " & errNo & vbCrLf & errMsg
' 4. 後始末へ進む
Resume CleanUp
End Sub
Application.ScreenUpdating を False にしたマクロは、終わるときに True へ戻すよう Microsoft Learn に書かれています。エラーで途中終了した場合も戻るように、設定を戻す行は CleanUp ラベルの下に集め、Resume CleanUp で必ず通す形にしています。
ログ出力のプロシージャ
マクロのブックと同じフォルダーの error.log に、1件を1行で追記します。
Public Sub WriteErrorLog(ByVal procName As String, ByVal errNo As Long, _
ByVal errMsg As String, ByVal errSrc As String)
Dim fileNo As Integer
Dim logPath As String
' ログ出力そのものでマクロが止まらないようにする
On Error Resume Next
logPath = ThisWorkbook.Path & "\error.log"
fileNo = FreeFile
Open logPath For Append As #fileNo
Print #fileNo, Format(Now, "yyyy-mm-dd hh:nn:ss") & vbTab & _
procName & vbTab & errNo & vbTab & errSrc & vbTab & errMsg
Close #fileNo
On Error GoTo 0
End Sub
使っている要素は次のとおりです。
| 要素 | 役割(Microsoft Learn の説明) |
|---|---|
FreeFile |
Open で使える、次の空きファイル番号を返す |
Open … For Append |
追記モードで開く。ファイルが無い場合は作成される |
Print # |
表示形式のデータをシーケンシャルファイルに書き込む |
Format(Now, "yyyy-mm-dd hh:nn:ss") |
現在の日時を、年-月-日 時:分:秒 の文字列にする(分は nn) |
ThisWorkbook.Path |
マクロのコードが入っているブックの保存先フォルダーのパス |
ログの1行は、日時・プロシージャ名・番号・発生元・説明の5項目をタブで区切った形になります。表計算ソフトにそのまま貼り付けて、番号ごとに並べ替えられます。
呼び出し元へエラーを伝え直す
下位のプロシージャではログだけ残し、利用者への表示は最上位のプロシージャに任せたい場合は、変数に写した内容で Err.Raise を実行して、呼び出し元へ伝え直します。
ErrHandler:
errNo = Err.Number
errMsg = Err.Description
errSrc = Err.Source
WriteErrorLog PROC_NAME, errNo, errMsg, errSrc
Application.ScreenUpdating = True
Err.Raise errNo, errSrc, errMsg
エラー処理ルーチンの中で起きたエラーは呼び出し元へ制御が渡る、という On Error の決まりを利用した書き方です。
エラー処理を書くときのチェックリスト
| 確認すること | 理由 |
|---|---|
モジュールの先頭に Option Explicit があるか |
変数名のつづり違いを、実行前に見つけられる |
ラベルの直前に Exit Sub/Exit Function があるか |
正常時にエラー処理ルーチンへ入らないようにする |
On Error Resume Next を On Error GoTo 0 で閉じているか |
意図しないエラーまで素通りさせない |
エラー処理ルーチンの先頭で Err.Number・Err.Description を変数に写しているか |
あとの処理で内容がリセットされても使える |
| 画面更新などの設定を、後始末のラベルで元に戻しているか | エラーで終わったときも設定が残らない |
Resume で再試行する箇所に、回数の上限があるか |
同じ行の繰り返しを止められる |
| オブジェクト変数を使う前に、Nothing かどうかを確かめているか | 91 を事前に避けられる |
よくある質問
Q. 実行時エラーとコンパイルエラーは何が違いますか? A. コンパイルエラーは、実行を始める前に文法や宣言の問題として知らされるものです。実行時エラーは、文法は正しくても、実行した時点の値や状態(シートが無い、セルが文字列、ファイルが無いなど)によって起きます。この記事の番号はすべて実行時エラーです。
Q. On Error Resume Next をマクロの先頭に書いておけば安心ですか?
A. エラーのダイアログは出なくなりますが、問題が起きた行も素通りして先へ進むため、結果が途中から意図と違っていても気づきにくくなります。試したい行だけを挟み、直後に Err.Number を確かめて On Error GoTo 0 で閉じる使い方が向いています。
Q. 1004 はメッセージが漠然としていて原因がわかりません。
A. VBA の外側(Excel など)から伝わってきたエラーに付く番号なので、止まった行で操作しているセル範囲・シート・ブックの指定を順に見直します。Err.Description と Err.Source をログに残しておくと、発生元の切り分けに役立ちます。
Q. 自分で決めたエラー番号は何番を使えばよいですか?
A. Microsoft Learn では、0〜512 はシステムエラー用に予約され、513〜65535 がユーザー定義に使える範囲とされています。クラスモジュールでは vbObjectError に番号を足した値を使います。定数に名前を付けておくと、Select Case で見分けやすくなります。
まとめ
- 実行時エラーは番号で原因の型が決まる。まず止まった行を確かめ、早見表の原因と照らし合わせる
- 1004 は Excel 側のオブジェクトの指定、9 は範囲外や存在しない名前、13 は型、91 は Nothing を見直す
- 424 はドットの左側(オブジェクトではない)、438 はドットの右側(そのメンバーが無い) と覚える
- On Error は GoTo ラベル・Resume Next・GoTo 0 の3形式。ラベルの前に Exit Sub を置き、Resume Next は短い区間で閉じる
- Resume は「同じ行」「次の行」「ラベル」の3つの戻り方。後始末は
Resume ラベルで必ず通す - エラー処理ルーチンでは、Err.Number と Err.Description を先に変数へ写す
- 独自のエラーは Err.Raise で 513 以降の番号を使い、ログには日時・プロシージャ名・番号・発生元・説明を残す
参考・出典
- Microsoft Learn「トラップできるエラー」 https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/trappable-errors
- Microsoft Learn「On Error ステートメント」 https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/on-error-statement
- Microsoft Learn「Resume ステートメント」 https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/resume-statement
- Microsoft Learn「Err オブジェクト」 https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/err-object
- Microsoft Learn「Raise メソッド」 https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/raise-method
- Microsoft Learn「アプリケーション定義またはオブジェクト定義のエラー」 https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/application-defined-or-object-defined-error
- Microsoft Learn エラー 9 の解説ページ https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/subscript-out-of-range-error-9
- Microsoft Learn エラー 13 の解説ページ https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/type-mismatch-error-13
- Microsoft Learn エラー 91 の解説ページ https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/object-variable-not-set-error-91
- Microsoft Learn「Range.Find メソッド (Excel)」 https://learn.microsoft.com/ja-jp/office/vba/api/excel.range.find
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「VBA実行時エラー一覧|1004・9・13・91の原因と対処」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。