この記事で分かること
- 実行時エラー91「オブジェクト変数が設定されていません」が発生する本質的な原因
- Setステートメントの忘れやFindメソッドの失敗など、具体的なエラー発生パターンと修正コード
- If Not … Is Nothing を使った、エラーを未然に防ぐ「防衛的プログラミング」の実装方法
- デバッグ機能(ローカルウィンドウやステップ実行)を活用した迅速な原因特定手順
実行時エラー91「オブジェクト変数またはWithブロック変数が設定されていません」とは
Excel VBAにおける実行時エラー91は、一言で言えば「中身が空っぽ(Nothing)のオブジェクト変数を操作しようとしたとき」に発生するエラーです。VBAには、単なる数値や文字列を格納する「基本データ型(Integer, Stringなど)」と、ワークシートやセル範囲、ブックなどを操作するための「オブジェクト型(Worksheet, Range, Workbookなど)」の2種類があります。
基本データ型は宣言した時点で初期値(0や空文字)が入るため、そのまま使ってもエラーにはなりません。しかし、オブジェクト型変数は宣言した直後は中身が「Nothing(何もない状態)」となっています。このNothingの状態のまま、変数に対して「セルに値を書き込む」「シートを選択する」といった具体的な命令を下そうとすると、VBAは「どの対象を操作すればよいのか分からない」と混乱し、実行時エラー91を吐き出して処理をストップさせてしまいます。また、Withブロックを使用する際に対象となるオブジェクトが適切に指定されていない場合も、同様のエラーが発生します。
実行時エラー91が発生する主な原因と具体的な解決策
エラー91が発生する場面は、主に以下の4つのパターンに集約されます。それぞれの現象と解決策を整理した一覧表を確認した上で、具体的なコード例と修正方法を見ていきましょう。
| 主な原因 | 発生する現象 | 基本的な対策 |
|---|---|---|
| Setキーワードの不足 | オブジェクト変数に値を代入する際、「Set」を書き忘れて代入に失敗している。 | オブジェクト型変数への代入時は、必ず「Set 変数 = オブジェクト」とする。 |
| Findメソッドの検索失敗 | Findで指定した値が見つからず、変数がNothingのままセル情報を操作しようとした。 | Find実行後、オブジェクトがNothingでないことを判定してから処理を行う。 |
| Withブロックの指定不備 | Withブロックに指定したオブジェクト自体がNothing、または正しく定義されていない。 | Withに渡すオブジェクトが正しく生成・取得できているか確認する。 |
| 変数の初期化忘れ | オブジェクト変数に実体を割り当てる(インスタンス化する)前にメソッドを呼び出した。 | 「New」キーワードや「Set」を使用して、必ずオブジェクトの実体を生成する。 |
原因1:Setキーワードの記述漏れ
VBAでは、通常の変数(数値や文字列)に値を代入する場合は「変数 = 値」と記述しますが、オブジェクト変数に代入する場合は必ず「Set 変数 = オブジェクト」と、先頭に「Set」を付けるルールがあります。これを書き忘れると、代入が行われず変数は「Nothing」のままとなり、エラー91が発生します。
不具合が発生するコード例(Bad)
Sub SetErrorSample()
Dim ws As Worksheet
' Setを忘れて直接代入しようとしている(エラーの原因)
ws = ThisWorkbook.Sheets("Sheet1")
' ここで実行時エラー91が発生する
MsgBox ws.Name
End Sub
修正後のコード例(Good)
Sub SetErrorFixed()
Dim ws As Worksheet
' オブジェクト変数には必ず「Set」を使用する
Set ws = ThisWorkbook.Sheets("Sheet1")
' 正常に動作する
MsgBox ws.Name
End Sub
解説:オブジェクト型変数に値を代入する際は、記述ルールとしてSetが必須です。エラーが発生した行の直前で、Setを書き忘れていないかチェックしましょう。
原因2:Findメソッドで検索対象が見つからなかった場合
実務のマクロで最も多いのが、特定の文字列をセルから探す「Findメソッド」に関連するエラーです。Findメソッドは、指定した検索値がシート内に存在しない場合、戻り値として「Nothing」を返します。検索結果を格納した変数がNothingであるにもかかわらず、そのセルの行番号や値を取得しようとすると、エラー91が引き起こされます。
不具合が発生するコード例(Bad)
Sub FindErrorSample()
Dim rng As Range
' 「存在しないデータ」を検索する
Set rng = Cells.Find(What:="存在しないデータ")
' 検索に失敗した場合、rngはNothingになるため、ここでエラー91が発生する
MsgBox rng.Address
End Sub
修正後のコード例(Good)
Sub FindErrorFixed()
Dim rng As Range
' 検索を実行
Set rng = Cells.Find(What:="存在しないデータ")
' 検索結果がNothing(見つからなかった)かどうかを判定する
If Not rng Is Nothing Then
' 見つかった場合のみ処理を実行する
MsgBox rng.Address
Else
' 見つかった場合の処理を記述
MsgBox "検索対象が見つかりませんでした。", vbExclamation
End If
End Sub
解説:Findメソッドを使用する際は、必ず If Not 変数 Is Nothing Then という条件分岐を挟むのがVBAプログラミングの鉄則です。これにより、データが見つからない場合でもマクロが強制終了するのを防ぐことができます。
原因3:Withブロックの参照先が正しく設定されていない
Withブロックは、特定のオブジェクトに対する複数の操作をまとめて記述できる便利な機能ですが、Withに指定したオブジェクト自体が取得できていない場合や、正しく定義されていない場合にもエラー91が発生します。
不具合が発生するコード例(Bad)
Sub WithErrorSample()
Dim targetSheet As Worksheet
' 変数targetSheetに何もセットしていない(Nothing状態)
' Nothingのオブジェクトに対してWithを開始しようとするため、エラー91が発生する
With targetSheet
.Range("A1").Value = "テスト"
End With
End Sub
修正後のコード例(Good)
Sub WithErrorFixed()
Dim targetSheet As Worksheet
' 対象となるシートを正しくセットする
Set targetSheet = ThisWorkbook.Sheets("Sheet1")
' オブジェクトが設定されていれば問題なく動作する
With targetSheet
.Range("A1").Value = "テスト"
End With
End Sub
解説:With文に指定する変数やオブジェクトが、その行を通過する時点で正しく初期化(Set)されているかを確認してください。
原因4:クラスモジュールのインスタンス化(New)の忘れ
VBAで自作のクラス(クラスモジュール)を利用する場合や、外部ライブラリ(DictionaryオブジェクトやFileSystemObjectなど)を利用する場合、オブジェクトを生成するための「New」キーワードが必要です。これを怠ると、実体のないクラスを呼び出すことになり、エラー91が発生します。
不具合が発生するコード例(Bad)
Sub ClassErrorSample()
Dim dict As Object ' もしくは Dictionary
' Newによるオブジェクトの作成(インスタンス化)をしていない
' 実体がないため、ここでエラー91が発生する
dict.Add "Key", "Value"
End Sub
修正後のコード例(Good)
Sub ClassErrorFixed()
Dim dict As Object
' CreateObject(または New)を使ってオブジェクトの実体を生成する
Set dict = CreateObject("Scripting.Dictionary")
' 正常に動作する
dict.Add "Key", "Value"
MsgBox dict("Key")
End Sub
解説:クラスや外部オブジェクトを扱う際は、単に変数宣言を行うだけでなく、CreateObjectやNewを伴うSetステートメントでメモリ上に実体を作り出す必要があります。
エラー91を予防するためのベストプラクティス
開発段階からエラー91の発生を想定し、適切な記述を心がけることで、安定して動作する頑健なマクロを作ることができます。以下の3つの予防策を取り入れましょう。
Nothingチェックの徹底
オブジェクト変数を操作する前には、常に「そのオブジェクトが本当に存在しているか(Nothingではないか)」をチェックする条件分岐を記述する癖をつけましょう。特に、外部からデータを取得する場合や、ユーザーの操作によって対象が変化するマクロでは必須の対策です。
If Not targetObj Is Nothing Then
' オブジェクトが存在する場合の安全な処理
Else
' オブジェクトが存在しない場合の安全なエラー回避処理
End If
Option Explicit の強制と変数の型指定
VBAのモジュール最上部に「Option Explicit」を記述し、変数の強制宣言を行うようにしてください。型指定(Dim ws As Worksheet など)を明示的に行うことで、VBAのエディタ(VBE)の補完機能や、コンパイルエラー(実行前の構文エラーチェック)が働き、単純な記述ミスを事前に防ぐことができます。また、Object型のような何でも入る「バリアント型」ではなく、極力「Worksheet」「Range」など具体的なオブジェクト型を指定(事前バインディング)することで、不適切な代入を防ぎやすくなります。
エラーハンドリング(On Error)の適切な組み込み
予期せぬ実行時エラーが発生した場合に、マクロを強制終了させてユーザーを困惑させないよう、適切なエラー処理ルーチンを組み込みます。エラーが発生した際に「何が原因で停止したのか」を分かりやすいメッセージで通知するように設計しましょう。
Sub SafeMacro()
On Error GoTo ErrorHandler
' メインの処理
Dim rng As Range
Set rng = Cells.Find("対象")
MsgBox rng.Address ' もしNothingならここでエラーになり、ErrorHandlerへジャンプする
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました。対象のデータが見つからなかった可能性があります。" & vbCrLf & _
"エラー番号: " & Err.Number & vbCrLf & _
"エラー内容: " & Err.Description, vbCritical, "エラー終了"
End Sub
どうしてもエラー91が解決しない場合のチェックリストと対処法
コードを見直してもエラー91が解消しない場合、デバッグ機能を使って問題が発生している箇所を特定する必要があります。以下のステップでデバッグを実行してください。
デバッグ実行(F8キー)で1行ずつ確認する
エラーが発生するプロシージャ(Sub)の中にカーソルを置き、キーボードの「F8キー」を押すと、コードを1行ずつ実行(ステップイン)できます。黄色いハイライトが表示され、どの行を実行した瞬間にエラー91が表示されるかを正確に特定してください。怪しい行の直前で変数の状態を確認するのがポイントです。
ローカルウィンドウで変数の状態を監視する
VBEのメニューから「表示」>「ローカルウィンドウ」を選択して有効にします。マクロをステップ実行している間、ローカルウィンドウには現在宣言されているすべての変数とその中身(値や型)がリアルタイムに表示されます。対象のオブジェクト変数の値が「Nothing」になっているタイミングを発見できれば、そこがバグの原因です。
前提条件が崩れていないか確認する
コード自体は正しくても、処理対象のExcelファイル側の状況が変わっているためにエラーになることがあります。
- 参照しているシートの名前が変更されていないか
- 検索対象の表に空行が混ざっていないか、またはシート保護がかかっていないか
- マクロが別の開いているブック(ActiveWorkbook)を対象に誤動作していないか
これらはコード側で「シート名やブック名を明示的に指定する」ことで防げます。ActiveSheet や Selection を多用せず、ThisWorkbook.Sheets("データ") のように対象を固定して記述しましょう。
VBAの不具合修正やシステム改修をプロに依頼するメリット
Excel VBAは手軽に導入できる反面、エラーの特定や改修には技術と時間を要します。特に、過去に他の担当者が作成したマクロ(いわゆる「野良マクロ」や「ブラックボックス化したシステム」)でエラー91が発生した場合、コード全体の構造を把握しなければならず、自力での解決が極めて困難になるケースが珍しくありません。
このような場合は、社内で長時間をかけて悩むよりも、開発会社やVBAのプロに修復を依頼することをお勧めします。プロに依頼することで、以下のようなメリットが得られます。
- 業務の即時復旧: エラーの原因をピンポイントで特定し、迅速に業務を再開できます。
- コードの最適化と高速化: エラー91の修正にとどまらず、不安定な処理を根本から見直し、動作のスピードアップやバグの起きにくい強固なプログラムへ書き換えます。
- 仕様書・ドキュメントの整備: 属人化していたマクロの仕様を整理し、今後のメンテナンス性を向上させます。
「エラーの解消に丸一日費やしてしまった」「自分で直したけれど、またすぐにエラーが出るのではないかと不安」という場合は、ぜひ一度専門の開発サービスへご相談ください。貴社の業務効率化を確実にサポートいたします。
エラー91とエラー13(型が一致しません)の違いは何ですか?
実行時エラー91「オブジェクト変数が設定されていません」は、オブジェクト型変数が「Nothing(中身が空)」の状態で操作を実行したときに発生します。これに対し、実行時エラー13「型が一致しません」は、変数に想定と異なるデータ型の値を代入しようとしたとき(例:数値型の変数に文字列を代入する、セルのエラー値を直接String型変数に格納するなど)に発生します。エラーが発生する根本原因が異なるため、対処法も異なります。
Findメソッドの後にNothingチェックをしないとどうなりますか?
Findメソッドで検索したデータがシート上に必ず存在していればエラーは発生しません。しかし、運用中にデータが削除されたり、入力ミスによって検索文字列がヒットしなくなったりすると、瞬時にNothingを返すため、Nothingチェック(If Not rng Is Nothing Then)がない場合はその時点でエラー91が発生し、マクロが強制終了してしまいます。マクロを安定して稼働させるためには、100%データが存在すると分かっている場合であっても、Nothingチェックを入れておくのがベストプラクティスです。
Setを記述したのにエラー91が発生するのはなぜですか?
Setキーワードを使用していても、代入しようとしている右辺のオブジェクト自体が「Nothing」を返している場合、左辺のオブジェクト変数も「Nothing」になってしまいます。例えば、Set ws = Sheets("Sheet1").Find(...) のような記述において、FindがNothingを返した場合などです。また、別のプロシージャや関数にオブジェクトを渡す際、参照渡し(ByRef)によって意図せず変数がNothingに書き換えられてしまっているケースも考えられます。ローカルウィンドウを用いて、どの段階で変数がNothingになっているか追跡してください。
ActiveWorkbookやActiveSheetを記述するとエラー91になりやすいですか?
はい。ActiveWorkbookやActiveSheetは、「今画面上で一番手前に表示されているブックやシート」を指します。マクロの実行中にユーザーが別のExcelファイルをクリックしたり、別のアプリケーションを操作したりすると、対象のシートが切り替わってしまいます。その結果、想定していたシートとは異なるシート上のセルが参照され、対象が存在せずにNothingになり、エラー91を引き起こす原因になります。マクロ内では、ThisWorkbook.Sheets("SheetName") のように対象を明示的に指定して記述することを強くお勧めします。