Excelマクロを実行したとき、「実行時エラー ’91’: オブジェクト変数またはWithブロック変数が設定されていません」というメッセージが表示されて処理が止まってしまう――このエラーはVBAでオブジェクトを扱うコードを書き始めた人がほぼ必ずぶつかる壁です。原因は一言で言えば「Setで中身を入れていないオブジェクト変数を使おうとした」ことですが、発生パターンは多岐にわたり、検索結果だけでは対処できないケースも多くあります。本記事では、エラー91が発生するすべてのパターンを場面ごとに整理し、その場でコピーして使える修正コードと合わせて徹底解説します。
目次
- 実行時エラー’91’とは何か――Nothingとオブジェクト変数の基礎
- 原因1:Setを使わずにオブジェクト変数に代入した
- 原因2:Nothingのままオブジェクトのプロパティ・メソッドを呼び出した
- 原因3:FindメソッドがNothingを返しているのに使おうとした
- 原因4:WithブロックのオブジェクトがNothingになっている
- 原因5:Setで解放した後にオブジェクトを使おうとした
- 原因6:関数がNothingを返しているのにチェックなしで使った
- 原因7:イベントプロシージャのオブジェクト引数がNothing
- Nothing判定ユーティリティ関数集
- デバッグ手順:どの変数がNothingかを特定する
- エラー91対応エラーハンドリングテンプレート
- エラー91 原因チェックリスト
- まとめ
実行時エラー’91’とは何か――Nothingとオブジェクト変数の基礎
エラー91を理解するには、まずVBAにおけるオブジェクト変数と Nothing の概念を押さえる必要があります。
VBAの変数には「値型」と「参照型(オブジェクト型)」の2種類があります。Long や String などの値型変数は宣言した時点でデフォルト値(0や空文字列)が入りますが、Worksheet や Range などのオブジェクト型変数は宣言しただけでは何も入っておらず、Nothing という空の状態になっています。
' オブジェクト変数を宣言した直後は Nothing(何も指していない)
Dim ws As Worksheet ' → ws は Nothing
Dim rng As Range ' → rng は Nothing
' Nothingのままプロパティにアクセスするとエラー91が発生する
Debug.Print ws.Name ' → 実行時エラー '91'
オブジェクト変数を使えるようにするには、Set キーワードを使って実際のオブジェクトを代入する必要があります。このSetによる代入を「オブジェクト参照のセット」と呼びます。エラー91は「Setが実行されないまま、またはSetが失敗したままオブジェクト変数を使おうとしたとき」に発生します。
' Setで実際のオブジェクトを代入してはじめて使える
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(1) ' ← これが必要
Debug.Print ws.Name ' → "Sheet1" などが表示される(正常)
' 使い終わったらNothingで解放するのが作法
Set ws = Nothing
エラー91が発生するパターンは大きく分けて次の3つです。
- Setを忘れた:宣言しただけで Set を書いていない
- Setが成功しなかった:条件分岐の中でSetが実行されなかった、Findが失敗した、など
- すでにNothingに戻った:
Set obj = Nothingで解放した後に使おうとした
原因1:Setを使わずにオブジェクト変数に代入した
オブジェクト変数への代入に Set を書き忘れると、VBAは値型の代入として解釈しようとしてエラー13(型が一致しません)になる場合と、そのままNothingのまま進んでエラー91になる場合があります。いずれにせよ Set の書き忘れはエラー91の直接原因になります。
エラーが起きるコード例
' Setを忘れるとエラー(13または91)
Dim ws As Worksheet
Dim rng As Range
Dim wb As Workbook
ws = ThisWorkbook.Sheets(1) ' → エラー13(Setが必要)
rng = ActiveSheet.Range("A1") ' → エラー13(Setが必要)
wb = ThisWorkbook ' → エラー13(Setが必要)
' Set自体は書いたが、代入先のオブジェクトが存在しない場合はNothingのまま
Dim col As Collection
Set col = Nothing ' 明示的にNothingを代入
col.Add "item" ' → 実行時エラー '91'
修正後のコード
' 必ずSetキーワードを使って代入する
Dim ws As Worksheet
Dim rng As Range
Dim wb As Workbook
Set ws = ThisWorkbook.Sheets(1)
Set rng = ActiveSheet.Range("A1:A10")
Set wb = ThisWorkbook
' オブジェクトを使う前に必ずNothingでないことを確認する
If Not ws Is Nothing Then
Debug.Print ws.Name
End If
If Not rng Is Nothing Then
rng.Interior.Color = RGB(255, 255, 200)
End If
' 処理後は解放する
Set ws = Nothing
Set rng = Nothing
Set wb = Nothing
Setが必要なオブジェクト型・不要な値型の早見表
- Set が必要(オブジェクト型):Workbook、Worksheet、Range、Chart、Shape、PivotTable、ListObject、Collection、Dictionary、FileSystemObject、ADODB系オブジェクト、自作クラスのインスタンスなど
- Set が不要(値型):Long、Integer、Double、Single、String、Boolean、Date、Byte、Currency、Variant(値を直接格納する場合)
迷ったときは TypeName(変数) を実行して確認するか、VBAエディタで変数名にカーソルを置いてオブジェクト型かどうかをポップアップで確認してください。
原因2:Nothingのままオブジェクトのプロパティ・メソッドを呼び出した
条件分岐や関数の戻り値によって、Set が特定の条件のときだけ実行されるコードでよく発生します。「ほとんどの場合は動くが、たまにエラーになる」という状況の原因の多くがこれです。
エラーが起きるコード例
' 条件によってはSetが実行されずNothingのまま進む
Dim ws As Worksheet
If ActiveSheet.Name = "集計" Then
Set ws = ActiveSheet
End If
' 上のIfに入らなかった場合、wsはNothingのまま
ws.Cells(1, 1).Value = "処理済" ' → 実行時エラー '91'
' ループ内でSetが失敗した場合
Dim targetWS As Worksheet
Dim sheetName As String
sheetName = "存在しないシート"
On Error Resume Next
Set targetWS = ThisWorkbook.Sheets(sheetName)
On Error GoTo 0
' エラーが出てもコードは続行されるが、targetWSはNothingのまま
targetWS.Activate ' → 実行時エラー '91'
修正後のコード(使う前に必ずNothingチェック)
' ========================================
' Nothingチェックを必ず入れるパターン
' ========================================
Sub SafeObjectAccess()
Dim ws As Worksheet
If ActiveSheet.Name = "集計" Then
Set ws = ActiveSheet
End If
' 使う前にNothingチェック
If ws Is Nothing Then
MsgBox "シート「集計」がアクティブでないため処理を中断します。", vbExclamation
Exit Sub
End If
ws.Cells(1, 1).Value = "処理済"
Set ws = Nothing
End Sub
' ========================================
' On Error Resume Nextを使ったSetとNothingチェックの標準パターン
' ========================================
Sub SafeSheetAccess()
Dim targetWS As Worksheet
Dim sheetName As String
sheetName = "集計シート"
' Setを試みる(失敗してもエラーで止まらない)
On Error Resume Next
Set targetWS = ThisWorkbook.Sheets(sheetName)
On Error GoTo 0
' Setが成功したか確認
If targetWS Is Nothing Then
MsgBox "シート「" & sheetName & "」が見つかりませんでした。" & vbCrLf & _
"シート名を確認してください。", vbCritical
Exit Sub
End If
' 安全に処理
targetWS.Cells(1, 1).Value = "OK"
Set targetWS = Nothing
End Sub
原因3:FindメソッドがNothingを返しているのに使おうとした
エラー91の原因として非常に多いのが、RangeオブジェクトのFindメソッドの戻り値チェック漏れです。Findは検索値が見つかった場合にRangeオブジェクトを、見つからなかった場合に Nothing を返します。このNothingチェックを忘れると、見つからない検索値が渡ったとたんにエラー91が発生します。
エラーが起きるコード例
' Findの戻り値をチェックせずに使うとエラー91
Dim foundCell As Range
Set foundCell = ActiveSheet.Range("A:A").Find(What:="検索値")
' foundCellがNothingの場合(見つからなかった場合)はエラー91
Debug.Print foundCell.Address ' → 実行時エラー '91'
foundCell.Interior.Color = vbYellow ' → 実行時エラー '91'
修正後のコード(Findの戻り値を必ずチェック)
' ========================================
' FindメソッドのNothingチェック標準パターン
' ========================================
Sub SafeFind()
Dim ws As Worksheet
Dim searchRange As Range
Dim foundCell As Range
Dim keyword As String
Set ws = ThisWorkbook.Sheets(1)
Set searchRange = ws.Range("A:A")
keyword = "検索値"
Set foundCell = searchRange.Find( _
What:=keyword, _
LookIn:=xlValues, _
LookAt:=xlWhole, _
MatchCase:=False)
' 必ずNothingチェックを行う
If foundCell Is Nothing Then
MsgBox "「" & keyword & "」は見つかりませんでした。", vbInformation
Else
MsgBox "「" & keyword & "」は " & foundCell.Address & " にあります。", vbInformation
foundCell.Interior.Color = vbYellow
End If
Set foundCell = Nothing
Set searchRange = Nothing
Set ws = Nothing
End Sub
FindNextを使ったループでのエラー91対策
' ========================================
' FindNextで複数セルを検索するときの安全なパターン
' ========================================
Sub SafeFindAll()
Dim ws As Worksheet
Dim searchRange As Range
Dim foundCell As Range
Dim firstAddr As String
Dim keyword As String
Dim count As Long
Set ws = ThisWorkbook.Sheets(1)
Set searchRange = ws.UsedRange
keyword = "対象"
count = 0
' 最初のFind
Set foundCell = searchRange.Find( _
What:=keyword, _
LookIn:=xlValues, _
LookAt:=xlPart)
' 最初のFindがNothingなら即終了
If foundCell Is Nothing Then
MsgBox "「" & keyword & "」は見つかりませんでした。", vbInformation
GoTo CleanUp
End If
' 最初に見つかったアドレスを記録(ループ終了判定に使う)
firstAddr = foundCell.Address
Do
count = count + 1
foundCell.Interior.Color = vbYellow
Debug.Print count & "件目: " & foundCell.Address
' 次を検索
Set foundCell = searchRange.FindNext(foundCell)
' FindNextがNothingを返した場合の保険
If foundCell Is Nothing Then Exit Do
Loop While foundCell.Address <> firstAddr ' 最初のセルに戻ったら終了
MsgBox count & " 件見つかりました。", vbInformation
CleanUp:
Set foundCell = Nothing
Set searchRange = Nothing
Set ws = Nothing
End Sub
原因4:WithブロックのオブジェクトがNothingになっている
Withブロックを使って複数のプロパティを設定するとき、WithキーワードにNothingのオブジェクトを渡すとエラー91が発生します。また、Withブロックの内側で誤って対象オブジェクトをNothingに設定してしまう場合も同様です。
エラーが起きるコード例
' wsがNothingの状態でWithに渡すとエラー91
Dim ws As Worksheet ' Nothingのまま
With ws ' → 実行時エラー '91'
.Cells(1, 1).Value = "テスト"
.Range("A1").Font.Bold = True
End With
' WithブロックのオブジェクトをNothingにして内部でアクセスするとエラー91
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(1)
With ws
.Cells(1, 1).Value = "開始"
Set ws = Nothing ' ← Withの途中でNothingにしてはいけない
.Cells(2, 1).Value = "終了" ' → 実行時エラー '91'
End With
修正後のコード
' Withに渡す前に必ずNothingチェックを行う
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(1)
' Withに入る前のガード処理
If ws Is Nothing Then
MsgBox "シートの取得に失敗しました。", vbCritical
Exit Sub
End If
With ws
.Cells(1, 1).Value = "テスト"
.Range("A1").Font.Bold = True
.Range("A1").Interior.Color = RGB(200, 230, 200)
End With
' WithブロックをEnd Withで抜けてから解放する
Set ws = Nothing
' ========================================
' ネストしたWithブロックを安全に使うパターン
' ========================================
Sub SafeNestedWith()
Dim ws As Worksheet
Dim rng As Range
Set ws = ThisWorkbook.Sheets(1)
Set rng = ws.Range("A1:C5")
If ws Is Nothing Or rng Is Nothing Then
MsgBox "オブジェクトの取得に失敗しました。", vbCritical
GoTo CleanUp
End If
With rng
.Value = "初期値"
.Font.Name = "メイリオ"
.Font.Size = 11
With .Interior
.Color = RGB(240, 248, 255)
.Pattern = xlSolid
End With
With .Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.Weight = xlThin
End With
End With
CleanUp:
Set rng = Nothing
Set ws = Nothing
End Sub
原因5:Setで解放した後にオブジェクトを使おうとした
Set obj = Nothing でオブジェクトを解放した後に、そのオブジェクト変数を使おうとするとエラー91が発生します。複数のプロシージャにまたがってオブジェクトを受け渡しているときや、エラーハンドラ内でCleanUpを行った後に誤ってオブジェクトを使おうとするケースで起きやすいです。
エラーが起きるコード例
' 解放した後にアクセスするとエラー91
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(1)
ws.Cells(1, 1).Value = "処理中"
Set ws = Nothing ' ここで解放
' 解放後に再びアクセスしようとするとエラー91
ws.Cells(1, 2).Value = "完了" ' → 実行時エラー '91'
' エラーハンドラでNothingにした後、処理に戻ろうとするケース
Sub ProblematicSub()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(1)
On Error GoTo ErrorHandler
ws.Cells(1, 1).Value = 1 / 0 ' ゼロ除算でエラー
Set ws = Nothing
Exit Sub
ErrorHandler:
Set ws = Nothing ' CleanUp
Resume Next ' 次の行に戻る → wsはNothingなのでエラー91の可能性
' ↑ Resume Nextは慎重に使う必要がある
End Sub
修正後のコード
' 解放前に処理をすべて完了させる
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(1)
' すべての処理を行ってから解放
ws.Cells(1, 1).Value = "処理中"
ws.Cells(1, 2).Value = "完了"
ws.Range("A1:B1").Font.Bold = True
Set ws = Nothing ' 最後にまとめて解放
' ========================================
' CleanUpラベルを使った安全な解放パターン
' ========================================
Sub SafeReleasePattern()
Dim ws As Worksheet
Dim rng As Range
On Error GoTo ErrorHandler
Set ws = ThisWorkbook.Sheets(1)
Set rng = ws.Range("A1:A10")
' ===== メイン処理 =====
rng.Value = "処理済"
rng.Interior.Color = RGB(200, 255, 200)
' =====================
MsgBox "処理完了", vbInformation
GoTo CleanUp
ErrorHandler:
MsgBox "エラーが発生しました。" & vbCrLf & _
"番号: " & Err.Number & vbCrLf & _
"内容: " & Err.Description, vbCritical
CleanUp:
' エラーの有無にかかわらず必ずここで解放する
' Nothingの状態で Set Nothing してもエラーにならないので安全
Set rng = Nothing
Set ws = Nothing
End Sub
原因6:関数がNothingを返しているのにチェックなしで使った
オブジェクトを返す関数(Function)では、処理が失敗した場合に Nothing を返すことがあります。呼び出し側でNothingチェックをしないまま戻り値を使うとエラー91が発生します。
エラーが起きるコード例
' シートを検索して返す関数
Function FindSheetByName(name As String) As Worksheet
On Error Resume Next
Set FindSheetByName = ThisWorkbook.Sheets(name)
On Error GoTo 0
' シートが存在しない場合、Nothingが返る
End Function
' 呼び出し側でNothingチェックをしていないとエラー91
Sub CallerSub()
Dim ws As Worksheet
Set ws = FindSheetByName("存在しないシート")
' wsがNothingの状態でアクセスするとエラー91
ws.Cells(1, 1).Value = "テスト" ' → 実行時エラー '91'
End Sub
修正後のコード(呼び出し側と関数側の両方で対策)
' ========================================
' Nothingを返す可能性がある関数の標準的な実装と呼び出しパターン
' ========================================
' 関数側:Nothingを返す可能性を明示するコメントを書く
' 戻り値がNothingのときは呼び出し側でチェックが必要
Function FindSheetByName(name As String) As Worksheet
' 見つからない場合はNothingを返す(エラーは発生しない)
On Error Resume Next
Set FindSheetByName = ThisWorkbook.Sheets(name)
On Error GoTo 0
End Function
' 範囲検索してRangeを返す関数(見つからない場合Nothing)
Function FindRangeByValue(ws As Worksheet, _
searchVal As String, _
Optional searchCol As Long = 1) As Range
If ws Is Nothing Then Exit Function ' 引数もNothingチェック
Set FindRangeByValue = ws.Columns(searchCol).Find( _
What:=searchVal, _
LookIn:=xlValues, _
LookAt:=xlWhole)
' 見つからない場合はNothingが返る
End Function
' 呼び出し側:戻り値がNothingでないことを確認してから使う
Sub SafeCallerSub()
Dim ws As Worksheet
Dim rng As Range
Set ws = FindSheetByName("データ")
' 関数の戻り値は必ずNothingチェック
If ws Is Nothing Then
MsgBox "「データ」シートが見つかりません。", vbCritical
Exit Sub
End If
Set rng = FindRangeByValue(ws, "山田太郎")
If rng Is Nothing Then
MsgBox "「山田太郎」は見つかりませんでした。", vbInformation
Else
MsgBox "「山田太郎」は " & rng.Address & " にあります。", vbInformation
rng.Interior.Color = vbCyan
End If
CleanUp:
Set rng = Nothing
Set ws = Nothing
End Sub
原因7:イベントプロシージャのオブジェクト引数がNothing
ボタンクリックイベントや、SelectionChange などのシートイベントで渡されるオブジェクト引数が、まれにNothingになっているケースがあります。また、イベントプロシージャ内でモジュールレベルの変数をオブジェクトとして使うとき、初期化されていない場合にエラー91が発生します。
エラーが起きるコード例
' モジュールレベルのオブジェクト変数が未初期化のまま使われる
Dim g_ws As Worksheet ' モジュールレベルで宣言
' ボタンクリックイベント
Private Sub CommandButton1_Click()
' g_wsが初期化されていないとエラー91
g_ws.Cells(1, 1).Value = "クリックされました" ' → エラー91
End Sub
修正後のコード
' モジュールレベル変数は使う前に必ず初期化する
Dim g_ws As Worksheet
' ブックを開いたとき(または初回ボタンクリック時)に初期化
Private Sub Workbook_Open()
Set g_ws = ThisWorkbook.Sheets("ログ")
End Sub
Private Sub CommandButton1_Click()
' 念のためNothingチェックを入れる
If g_ws Is Nothing Then
Set g_ws = ThisWorkbook.Sheets("ログ")
End If
If g_ws Is Nothing Then
MsgBox "「ログ」シートが見つかりません。", vbCritical
Exit Sub
End If
g_ws.Cells(g_ws.Rows.Count, 1).End(xlUp).Offset(1, 0).Value = _
Format(Now(), "yyyy/mm/dd HH:mm:ss") & " クリックされました"
End Sub
' SelectionChangeイベントでの安全なオブジェクト操作
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
' Targetは通常Nothingにならないが念のためチェック
If Target Is Nothing Then Exit Sub
' 選択が複数セルにまたがる場合の処理
If Target.Cells.Count > 1 Then Exit Sub
' 特定列(A列)が選択されたときだけ処理
If Target.Column <> 1 Then Exit Sub
' 安全に処理
Application.EnableEvents = False
Target.Interior.Color = RGB(255, 255, 200)
Application.EnableEvents = True
End Sub
Nothing判定ユーティリティ関数集
エラー91対策として汎用的に使えるユーティリティ関数をまとめました。標準モジュールに追加しておくとプロジェクト全体で再利用できます。
' ========================================
' エラー91対策 Nothing判定ユーティリティ集
' 標準モジュールに貼り付けて使用
' ========================================
' ----- オブジェクトがNothingでないか確認 -----
Function IsSet(obj As Object) As Boolean
IsSet = Not (obj Is Nothing)
End Function
' ----- シートの存在確認とオブジェクト取得 -----
Function GetSheetSafe(sheetName As String, _
Optional wb As Workbook) As Worksheet
If wb Is Nothing Then Set wb = ThisWorkbook
On Error Resume Next
Set GetSheetSafe = wb.Sheets(sheetName)
On Error GoTo 0
' 戻り値がNothingの場合、呼び出し側でチェックが必要
End Function
' ----- 範囲の安全な取得 -----
Function GetRangeSafe(ws As Worksheet, addr As String) As Range
If ws Is Nothing Then Exit Function
On Error Resume Next
Set GetRangeSafe = ws.Range(addr)
On Error GoTo 0
End Function
' ----- Findの安全なラッパー -----
Function FindCellSafe(searchRange As Range, _
keyword As String, _
Optional lookAt As XlLookAt = xlWhole, _
Optional matchCase As Boolean = False) As Range
If searchRange Is Nothing Then Exit Function
Set FindCellSafe = searchRange.Find( _
What:=keyword, _
LookIn:=xlValues, _
LookAt:=lookAt, _
MatchCase:=matchCase)
' 見つからない場合はNothingを返す
End Function
' ----- ブックが開かれているか確認して取得 -----
Function GetOpenWorkbook(wbName As String) As Workbook
On Error Resume Next
Set GetOpenWorkbook = Workbooks(wbName)
On Error GoTo 0
End Function
' ----- 複数オブジェクトをまとめて解放 -----
Sub ReleaseObjects(ParamArray objs() As Variant)
Dim i As Long
For i = LBound(objs) To UBound(objs)
If IsObject(objs(i)) Then
If Not objs(i) Is Nothing Then
Set objs(i) = Nothing
End If
End If
Next i
End Sub
' ========================================
' 使用例
' ========================================
Sub UtilityUsageExample()
Dim ws As Worksheet
Dim rng As Range
Dim cell As Range
' シートを安全に取得
Set ws = GetSheetSafe("データ入力")
If Not IsSet(ws) Then
MsgBox "「データ入力」シートが見つかりません。", vbCritical
Exit Sub
End If
' 範囲を安全に取得
Set rng = GetRangeSafe(ws, "A1:A100")
If Not IsSet(rng) Then
MsgBox "範囲の取得に失敗しました。", vbCritical
GoTo CleanUp
End If
' Findを安全に実行
Set cell = FindCellSafe(rng, "山田太郎")
If Not IsSet(cell) Then
MsgBox "「山田太郎」は見つかりませんでした。", vbInformation
GoTo CleanUp
End If
cell.Interior.Color = vbYellow
MsgBox "見つかりました: " & cell.Address, vbInformation
CleanUp:
Set cell = Nothing
Set rng = Nothing
Set ws = Nothing
End Sub
デバッグ手順:どの変数がNothingかを特定する
エラー91が発生したとき、どのオブジェクト変数がNothingになっているかを素早く特定する方法です。
ステップ1:エラー行を確認してオブジェクト変数を特定する
エラーダイアログの「デバッグ」ボタンを押すと、VBAエディタでエラー行が黄色くハイライトされます。その行でどのオブジェクト変数を使っているかを確認してください。
ステップ2:イミディエイトウィンドウでNothingかどうかを確認する
' デバッグモード中にイミディエイトウィンドウ(Ctrl+G)で以下を入力
' ?(ws Is Nothing) → Trueならwsはなにも設定されていない
' ?(rng Is Nothing) → Trueならrngはなにも設定されていない
' ?TypeName(ws) → "Nothing"と表示されれば未設定
ステップ3:各変数の状態を一括チェックするデバッグコードを挿入する
' エラーが起きる処理の直前に以下のデバッグコードを一時的に挿入する
Sub DebugObjectStatus()
Dim ws As Worksheet
Dim rng As Range
Dim cell As Range
' ... (Setの処理) ...
' オブジェクトの状態を一括確認
Debug.Print "=== オブジェクト変数の状態確認 ==="
Debug.Print "ws : " & IIf(ws Is Nothing, "Nothing(未設定)", TypeName(ws) & " - " & ws.Name)
Debug.Print "rng : " & IIf(rng Is Nothing, "Nothing(未設定)", TypeName(rng) & " - " & rng.Address)
Debug.Print "cell : " & IIf(cell Is Nothing, "Nothing(未設定)", TypeName(cell) & " - " & cell.Address)
Debug.Print "=================================="
End Sub
ステップ4:F8ステップ実行でSetが実行されているかを追う
VBAエディタでF8キーを押すと1行ずつ実行するステップ実行モードになります。Setキーワードのある行を通過したあと、イミディエイトウィンドウで ? TypeName(変数名) と入力してオブジェクトが正常に設定されたかを確認してください。Setが条件分岐の中にある場合、その分岐を通過したかどうかも確認します。
エラー91対応エラーハンドリングテンプレート
' ========================================
' エラー91に対応したエラーハンドリングテンプレート
' ========================================
Sub MainProcess()
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim rng As Range
Dim cell As Range
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
On Error GoTo ErrorHandler
' オブジェクトの取得
Set ws1 = GetSheetSafe("データ入力")
Set ws2 = GetSheetSafe("集計")
' 取得後のNothingチェック
If ws1 Is Nothing Then
Err.Raise 91, "MainProcess", "「データ入力」シートが見つかりません。"
End If
If ws2 Is Nothing Then
Err.Raise 91, "MainProcess", "「集計」シートが見つかりません。"
End If
Set rng = ws1.Range("A2:A100")
' ===== メイン処理 =====
Set cell = FindCellSafe(rng, "処理対象")
If Not cell Is Nothing Then
ws2.Cells(1, 1).Value = cell.Value
End If
' =====================
MsgBox "処理完了", vbInformation
GoTo CleanUp
ErrorHandler:
Dim msg As String
Select Case Err.Number
Case 91
msg = "オブジェクト変数が設定されていません(エラー91)。" & vbCrLf & vbCrLf & _
"確認してください:" & vbCrLf & _
"・Setキーワードを使ってオブジェクトを代入しているか" & vbCrLf & _
"・Findや関数の戻り値がNothingでないか確認しているか" & vbCrLf & _
"・解放済み(Nothing)のオブジェクトを使っていないか"
Case 9
msg = "シート・配列の添字が有効範囲にありません(エラー9)。"
Case 1004
msg = "Excelオブジェクトへの操作が失敗しました(エラー1004)。"
Case Else
msg = "予期しないエラーが発生しました。"
End Select
MsgBox msg & vbCrLf & vbCrLf & _
"エラー番号:" & Err.Number & vbCrLf & _
"内容:" & Err.Description & vbCrLf & _
"発生元:" & Err.Source, _
vbCritical, "実行時エラー " & Err.Number
CleanUp:
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.CutCopyMode = False
Set cell = Nothing
Set rng = Nothing
Set ws2 = Nothing
Set ws1 = Nothing
End Sub
エラー91 原因チェックリスト
エラー91が発生したとき、以下のリストを上から順番に確認してください。
- オブジェクト変数への代入に
Setキーワードを使っているか - 値型変数(Long・Stringなど)に誤って
Setを使っていないか - オブジェクト変数を使う前に
If obj Is Nothing ThenでNothingチェックをしているか - 条件分岐や例外処理の中でSetが実行されない経路がないか(F8ステップ実行で確認)
- Findメソッドの戻り値をNothingチェックなしに使っていないか
- FindNextループで最初のFindがNothingを返した場合の処理があるか
- Withブロックに渡すオブジェクトが Withの開始前にNothingでないことを確認しているか
- WithブロックのEnd Withに到達する前に 対象オブジェクトをNothingにしていないか
Set obj = Nothingで解放した後に、同じ変数を再使用しようとしていないか- オブジェクトを返す関数の戻り値が Nothing を返す可能性があり、呼び出し側でNothingチェックをしているか
- モジュールレベルのオブジェクト変数が使用前に必ず初期化されているか(Workbook_Openイベントで初期化するなど)
- イミディエイトウィンドウで
? TypeName(変数名)を実行して “Nothing” と表示されていないか確認したか
まとめ
実行時エラー’91’「オブジェクト変数またはWithブロック変数が設定されていません」は、Nothingのままのオブジェクト変数を使おうとしたときに発生します。原因は必ずSetによる代入の失敗・漏れ・解放後の使用のいずれかです。本記事で解説した内容の要点は次のとおりです。
- Setの書き忘れ:オブジェクト変数への代入には必ず
Setを使う。迷ったら TypeName で型を確認する - Nothingチェック:Setの後は必ず
If obj Is Nothing Thenで確認してから使う - Findの戻り値:Find・FindNextの結果は必ずNothingチェックを行う。FindNextループでは最初のFindがNothingの場合の処理も必須
- Withブロック:Withに渡す前にNothingチェックし、Withの内側でオブジェクトをNothingにしない
- 解放後の使用:
Set obj = Nothing後に同変数を使わない。CleanUpラベルパターンでまとめて解放する - 関数の戻り値:オブジェクトを返す関数の戻り値は必ず呼び出し側でNothingチェックを行う
- デバッグ:イミディエイトウィンドウで
? TypeName(変数名)を実行するのが最速の原因特定手段
本記事で紹介したユーティリティ関数集(GetSheetSafe・GetRangeSafe・FindCellSafe・IsSet)を標準モジュールに一度追加しておけば、以後のすべてのマクロでエラー91への耐性が大幅に向上します。「オブジェクトを使う前に必ずNothingチェックをする」という習慣がエラー91を根絶する唯一の方法です。