更新日:、 作成日:

VBA エラー処理をする (On Errer GoTo)

はじめに

Excel VBA マクロでエラー処理をする方法を紹介します。

On Error GoTo ラベル名 から、ラベルの位置からエラー処理できます。

On Error Resume Next から、エラーを無視して処理を継続できます。

On Error GoTo 0 から、エラー処理を無効にできます。

エラー情報を取得するには「エラー情報を取得する」をご覧ください。
デバッグについては「デバッグの仕方」をご覧ください。

エラー処理する方法

エラーが発生したときにできることは、次の通りです。

  • キャッチする
  • 無視する
  • 中断してデバッグする (開発用)

キャッチする:通常はエラーをキャッチします。処理をそこで中断して、適切なエラー処理をすることです。意図しないエラーに対処するためにも、エラーをキャッチする必要があります。

無視する:無視するとは、エラーが発生していないかのように処理を継続させることです。ただし不正な値のままプログラムを動かすと、さらなるエラーが発生する危険性があります。意図したエラーだけを無視します。

中断してデバッグする:意図しないエラーは、エラー発生時に中断してデバッグできます。

中断してデバッグするには「エラー発生時に中断する」をご覧ください。

エラー処理をしないときは、エラーメッセージが表示されマクロが終了します。

エラー処理をする (On Error GoTo)

GoTo 文」を使用して、エラーが発生したときに指定したラベルに処理を移動できます。他の言語では Try-Catch です。

On Error GoTo ラベル名 のように入力します。エラーが発生したときに指定したラベルの位置に処理を移動します。

エラー処理のラベル名を付けるには ラベル名: のように入力します。

Sub 実行()
On Error GoTo Catch ' エラーが発生したら Catch へ移動する

    ' 処理

    Exit Sub
Catch: ' エラーが発生したらここから処理が始まる

    ' エラー処理

End Sub

Catch: の前に Exit Sub または Exit Function を入力します。これはエラーが発生していないときにエラー処理を行わないように、そこで関数を抜けます。

キャッチしたエラー処理の中で発生したエラーはキャッチできません。エラーメッセージが表示されます。対処法は下記の「Finally」をご覧ください。

キャッチできる範囲

On Error の行から、その関数を抜けるまでに発生するエラーをキャッチします。その前に発生したエラーはキャッチできないので、必ず関数の直下に入力します。

Sub 実行()

    ' キャッチできない

On Error GoTo Catch 

    ' キャッチできる

End Sub

範囲内で別の関数を呼び出すと、その関数でエラー処理をしていなければ、そこで発生したエラーもキャッチできます。

エラー処理の後始末をする (Finally)

正常処理とエラー処理の両方で、同じように後始末したいことがよくあります。その処理が Finally です。

VBA のエラー処理に Finally の機能はありませんが、上記のエラー処理を組み合わせて同じようなことができます。

Resume ラベル名 のように入力して、キャッチしたエラー処理の中から指定したラベルに処理を移動できます。Resume 後は On Error でエラー処理を上書きできます。

Sub 実行()
On Error GoTo Catch 

    ' 正常な処理
    Debug.Print("正常")

Finally:
On Error Resume Next

    ' Finally の処理
    Debug.Print("Finally")

    Exit Sub  
Catch:

    ' エラー処理
    Debug.Print("エラー")

    Resume Finally ' Finally へ移動する
End Sub

Finally: の中でエラーを発生させないようにします。保険の意味で On Error Resume Next を入力しています。Resume Next については下記の「エラーを無視する」をご覧ください。

Catch: の中でエラーを発生させてはいけません。そのエラーはキャッチできずエラーメッセージが表示され、マクロが終了します。

Catch: で発生するエラーを無視するには、次のように Catch2: を追加します。

Sub 実行()
On Error GoTo Catch 

    ' 正常な処理
    Debug.Print("正常")

Finally:
On Error Resume Next

    ' Finally の処理
    Debug.Print("Finally")

Exit Sub 
Catch:

    ' 必要ならエラー情報を取得する
    Debug.Print(Err.Description)

Resume Catch2 ' エラー処理は Catch2 で行う
Catch2:
On Error Resume Next

    ' エラー処理
    Debug.Print("エラー")

    GoTo Finally
End Sub

Catch: ではエラー処理を行いません。発生したエラー情報だけを取得し、エラーが発生しないようにします。エラー処理は Catch2: で行います。

Catch2: でエラー処理を行います。Catch: から Resume で呼ばれるので、エラーを無視できます。

見ての通りエラー処理をするほどコードが見づらくなります。エラー処理を入力することで、逆にエラーが発生しないように注意します。

エラーを無視する (On Error Resume Next)

エラーを無視して処理を継続できます。

On Error Resume Next を入力します。エラーが発生したときは、次の行に処理を移動できます。

Sub 実行()
On Error Resume Next ' エラーが発生したら次の行へ移動する

    ' 処理

End Sub

変数に代入するときにエラーが発生したときは、変数の値は変更されません。

Sub 実行()
On Error Resume Next

    Dim i As Integer
    i = 1
    i = "a" ' エラー、無視される

    Debug.Print(i) ' 1
End Sub

この動作を利用して関数が正常に実行されるときは値が返され、エラーが発生したときは何も設定されないので次のようにエラー判定ができます。

Sub 実行()
On Error Resume Next
    Dim fso As Object
    ' エラーが発生するかもしれない処理
    Set fso = CreateObject("Hoge.Hoge")
    
    ' エラーが発生したときは Nothing のまま
    If fso Is Nothing Then
        ' エラー処理
    End If
    
    Set fso = Nothing
End Sub

無視できる範囲

「エラー処理をする」と同じで On Error Resume Next の行から関数を抜けるまでです。

絶対にマクロを中断したくないときは、最初に呼び出される関数に入力します。これですべてのエラーを無視できます。ただし、その後に正常な処理ができる保証がないのでオススメしません。

エラー処理を無効にする (On Error GoTo 0)

On Error GoTo 0 を入力します。その関数内のエラー処理を無効にできます。

Sub 実行()
On Error Resume Next

    ' 無視する

On Error GoTo 0 ' 以降はエラー処理しない

    Dim i As Integer
    i = "a"  ' エラー

End Sub

無効にできる範囲

「エラー処理をする」と同じで On Error GoTo 0 の行から関数を抜けるまでです。それを呼び出した関数のエラー処理は無効になりません。

Sub 実行()
On Error Resume Next 

    ' 無視する

    Call Tips ' Tips 関数で GoTo 0 をしているので、その中だけ無効になる

    ' 無視する

End Sub

Sub Tips()
On Error GoTo 0 ' この関数のエラー処理を無効にする

End Sub

エラー処理を上書きする

On Error GoTo や On Error Resume Next の範囲内で別のエラー処理を入力すると、上書きできます。

Sub 実行()
On Error Resume Next

    ' 無視する

On Error GoTo Catch ' Resume Next を上書きする

    ' キャッチする

    Exit Sub
Catch: 

    ' エラー処理

End Sub

範囲内で別の関数を呼び出したときに、その関数にエラー処理が入力されているときは、その範囲内だけが上書きされます。

Sub 実行()
On Error Resume Next 

    ' 無視する

    Call Tips ' Tips 関数でエラー処理しているので、その中だけ上書きされる

    ' 無視する

End Sub

Sub Tips()
On Error GoTo Catch ' 呼び出し元でエラー処理していても、この関数の Catch へ移動する

    ' キャッチする

    Exit Sub
Catch:

End Sub

キャッチしたエラー処理の中では上書きできません。

Sub 実行()
On Error GoTo Catch 

    Dim i As Integer
    i = "a" ' エラー、Catch へ移動する 

    Exit Sub
Catch: 
On Error Resume Next ' エラー処理の中の On Error では上書きできない、意味のないコード

    i = "a" ' エラー、無視されない

End Sub