Excelマクロを実行したとき「実行時エラー ‘438’: オブジェクトはこのプロパティまたはメソッドをサポートしていません」というエラーが発生して処理が止まってしまう――このエラーは、存在しないプロパティ名・メソッド名をオブジェクトに対して呼び出したときに発生するVBAの代表的なエラーです。スペルミスや大文字・小文字の違い程度の原因から、ExcelバージョンによるAPIの差異、オブジェクトの型の取り違えまで、原因は幅広くあります。本記事では、エラー438が発生するすべての主要パターンをコード付きで体系的に解説し、その場で使える修正方法と予防策を詳しくお伝えします。
目次
- 実行時エラー’438’とは何か
- 原因1:プロパティ名・メソッド名のスペルミス
- 原因2:オブジェクトの型の取り違え
- 原因3:Excelバージョン間の機能差異
- 原因4:ADODBやDAOなどの外部オブジェクトのメソッドミス
- 原因5:グラフ・図形オブジェクトへのアクセスミス
- 原因6:廃止・変更されたオブジェクト(InternetExplorerなど)
- 原因7:自作クラスに存在しないメンバーへのアクセス
- オブジェクトブラウザを使った正しいプロパティ・メソッドの調べ方
- デバッグ手順:エラー438の原因を素早く特定する
- エラーハンドリングテンプレート
- エラー438 原因チェックリスト
- まとめ
実行時エラー’438’とは何か
エラー438「オブジェクトはこのプロパティまたはメソッドをサポートしていません(Object doesn’t support this property or method)」は、VBAがオブジェクトに対してプロパティの読み書きやメソッドの呼び出しを試みたとき、そのオブジェクトが指定された名前のプロパティ・メソッドを持っていない場合に発生します。
エラー91(Nothingのオブジェクトへのアクセス)とよく混同されますが、エラー438はオブジェクトは存在しているが、呼び出した名前が間違っているという点で明確に異なります。主な発生パターンは次のとおりです。
- プロパティ名・メソッド名のスペルミスや大文字・小文字の誤り
- 取得したオブジェクトの型が意図したものと異なる(RangeのつもりがWorksheetになっているなど)
- 古いコードをそのまま使っているが、Excelのバージョンアップで廃止・変更されたプロパティ
- ADODBやDAOなどの外部ライブラリで、オブジェクトの種類に応じたメソッドを誤って呼び出している
- InternetExplorerオブジェクトなどすでに廃止されたオブジェクトを使おうとしている
- 自作クラスモジュールに定義していないプロパティ・メソッドを外部から呼び出している
エラー438はコンパイル時ではなく実行時に発生するのが特徴です。これは変数を Object 型や Variant 型で宣言している場合、VBAがコンパイル時に型チェックを行わないためです。具体的な型(Worksheet・Rangeなど)で宣言するほうが、入力補完も効いてエラーを未然に防ぎやすくなります。
原因1:プロパティ名・メソッド名のスペルミス
エラー438の原因として最も多いのが、プロパティ名・メソッド名のスペルミスです。VBAのプロパティ名やメソッド名は英語であるため、日本語母語のユーザーにとって見落としやすく、特に似た名前が複数存在する場合に混乱しやすいです。
エラーが起きるコード例
' よくあるスペルミスの例
' NG:Valueの複数形(Values)はRangeオブジェクトには存在しない
ActiveSheet.Range("A1").Values = "テスト" ' → エラー438
' OK
ActiveSheet.Range("A1").Value = "テスト"
' NG:Colorの末尾にsを付けてしまう
ActiveSheet.Range("A1").Interior.Colors = RGB(255, 0, 0) ' → エラー438
' OK
ActiveSheet.Range("A1").Interior.Color = RGB(255, 0, 0)
' NG:AutoFitを誤字
ActiveSheet.Columns("A").AutoFits ' → エラー438
' OK
ActiveSheet.Columns("A").AutoFit
' NG:EntireRowをEntireRowsと誤記
ActiveSheet.Range("A1").EntireRows.Delete ' → エラー438
' OK
ActiveSheet.Range("A1").EntireRow.Delete
' NG:UsedRangeをUseRangeと誤記
Dim lastRow As Long
lastRow = ActiveSheet.UseRange.Rows.Count ' → エラー438
' OK
lastRow = ActiveSheet.UsedRange.Rows.Count
スペルミスを防ぐための3つの対策
- 変数を具体的な型で宣言する:
Dim ws As ObjectではなくDim ws As Worksheetと宣言するとVBAエディタの入力補完(IntelliSense)が機能し、存在するプロパティ・メソッドだけが一覧表示されます - オブジェクトブラウザで確認する:VBAエディタでF2キーを押してオブジェクトブラウザを開き、クラス名とメンバー名を正確に確認します
- 入力補完を積極的に使う:オブジェクト変数の後にピリオドを入力したとき自動表示されるメンバー一覧から選択することでスペルミスをゼロにできます
' 入力補完が機能する宣言の書き方(推奨)
Dim ws As Worksheet ' WorksheetのプロパティがIntelliSenseで表示される
Dim rng As Range ' RangeのプロパティがIntelliSenseで表示される
Dim wb As Workbook ' WorkbookのプロパティがIntelliSenseで表示される
' 入力補完が機能しない宣言(非推奨)
Dim ws As Object ' ← Object型ではIntelliSenseが効かない
Dim rng As Variant ' ← Variant型でもIntelliSenseが効かない
原因2:オブジェクトの型の取り違え
取得したオブジェクトが意図した型と異なる場合、そのオブジェクトが持っていないプロパティ・メソッドを呼び出そうとしてエラー438が発生します。特に ActiveCell・Selection・ActiveSheet などの「現在の状態に依存するオブジェクト」を使うときに起きやすいです。
エラーが起きるコード例
' Selectionはその時点での選択内容によって型が変わる
' セルを選択しているときはRange型だが、グラフを選択しているとChart型になる
Selection.Value = "テスト" ' グラフが選択されていると → エラー438
' ActiveSheetはWorksheetとは限らない
' グラフシート(Chart)がアクティブのとき
ActiveSheet.Cells(1, 1).Value = "テスト" ' → エラー438(ChartにはCellsがない)
' RangeのつもりでWorksheetのメソッドを呼ぼうとしている
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets(1)
ws.Value = "テスト" ' → エラー438(WorksheetにはValueがない)
修正後のコード(TypeNameで型確認・具体的な参照に変更)
' ========================================
' オブジェクトの型を確認してから処理する
' ========================================
Sub SafeSelectionAccess()
' Selectionの型を確認してから処理
If TypeName(Selection) = "Range" Then
Selection.Value = "テスト"
Selection.Font.Bold = True
ElseIf TypeName(Selection) = "ChartArea" Or _
TypeName(Selection) = "Chart" Then
MsgBox "グラフが選択されています。セルを選択してから実行してください。", vbExclamation
Else
MsgBox "想定外の選択状態です。型:" & TypeName(Selection), vbExclamation
End If
End Sub
' ActiveSheetの型確認
Sub SafeActiveSheetAccess()
' WorksheetとChartシートを区別する
If TypeName(ActiveSheet) = "Worksheet" Then
Dim ws As Worksheet
Set ws = ActiveSheet
ws.Cells(1, 1).Value = "処理済"
Else
MsgBox "アクティブシートがワークシートではありません。" & vbCrLf & _
"型:" & TypeName(ActiveSheet), vbExclamation
End If
End Sub
' ========================================
' Selectionを使わずに明示的にオブジェクトを指定する(推奨)
' ========================================
Sub ExplicitObjectAccess()
' Selectionに依存せず、シートとセルを直接指定する
Dim ws As Worksheet
Dim rng As Range
Set ws = ThisWorkbook.Sheets("データ入力")
Set rng = ws.Range("B2:B50")
rng.Value = "処理済"
rng.Font.Bold = True
rng.Interior.Color = RGB(200, 255, 200)
Set rng = Nothing
Set ws = Nothing
End Sub
TypeNameで確認できる主なオブジェクト型
"Worksheet":通常のワークシート"Chart":グラフシート(ChartシートはCellsやRangeを持たない)"Range":セル範囲"ChartArea":埋め込みグラフのチャートエリア"Nothing":未設定のオブジェクト変数(→ エラー91の原因)"OLEObject":ActiveXコントロールや埋め込みオブジェクト
原因3:Excelバージョン間の機能差異
古いExcelで作成されたマクロをExcel 2016/2019/2021/Microsoft 365で実行したとき、または逆に新しいAPIを旧バージョンで使おうとしたときにエラー438が発生することがあります。バージョン間でプロパティ名が変更・廃止されたケースが代表例です。
よく問題になるバージョン差異の例
' ----------------------------------------
' 例1:スパークラインは Excel 2010以降のみ
' ----------------------------------------
' Excel 2007以前で実行するとエラー438
ActiveSheet.SparklineGroups.Add Type:=xlSparkLine, _
SourceData:="B2:M2"
' 対処:バージョン確認を追加する
If Val(Application.Version) >= 14 Then ' 14 = Excel 2010
ActiveSheet.SparklineGroups.Add Type:=xlSparkLine, SourceData:="B2:M2"
Else
MsgBox "スパークラインはExcel 2010以降で使用できます。", vbExclamation
End If
' ----------------------------------------
' 例2:WorksheetFunction.Forecast_ETSは Excel 2016以降
' ----------------------------------------
If Val(Application.Version) >= 16 Then ' 16 = Excel 2016
Dim result As Double
' Forecast_ETSを使った処理
Else
MsgBox "この関数はExcel 2016以降で使用できます。", vbExclamation
End If
' ----------------------------------------
' 例3:xlCSVUTF8はExcel 2016以降
' ----------------------------------------
Dim saveFormat As Long
If Val(Application.Version) >= 16 Then
saveFormat = 62 ' xlCSVUTF8
Else
saveFormat = 6 ' xlCSV(Shift-JIS)
End If
ActiveWorkbook.SaveAs ThisWorkbook.Path & "\output.csv", saveFormat
Excelのバージョン番号早見表
Application.Versionが"11.0":Excel 2003Application.Versionが"12.0":Excel 2007Application.Versionが"14.0":Excel 2010Application.Versionが"15.0":Excel 2013Application.Versionが"16.0":Excel 2016 / 2019 / 2021 / Microsoft 365(すべて16.0)
' バージョンを数値で安全に比較するユーティリティ
Function ExcelVersionNumber() As Double
ExcelVersionNumber = CDbl(Application.Version)
End Function
' 使用例
Sub VersionCheckExample()
Dim ver As Double
ver = ExcelVersionNumber()
Debug.Print "Excelバージョン番号: " & ver
If ver >= 16 Then
Debug.Print "Excel 2016以降の機能が使用可能です"
ElseIf ver >= 14 Then
Debug.Print "Excel 2010〜2013の機能が使用可能です"
Else
Debug.Print "旧バージョンのExcelです"
End If
End Sub
原因4:ADODBやDAOなどの外部オブジェクトのメソッドミス
データベース操作でよく使われるADODB(ActiveX Data Objects)やDAO(Data Access Objects)では、オブジェクトの種類によって使えるメソッドが厳密に決まっています。ConnectionオブジェクトにRecordsetのメソッドを使うなど、オブジェクトの取り違えが起きるとエラー438が発生します。
エラーが起きるコード例
' ConnectionオブジェクトにRecordset系のメソッドを使おうとするとエラー438
Dim conn As Object
Set conn = CreateObject("ADODB.Connection")
conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=C:\data\sample.accdb;"
conn.Open
' ConnectionにはMoveNextはない(RecordsetのメソッドをConnectionに呼ぼうとしている)
conn.MoveNext ' → 実行時エラー '438'
' Recordsetを閉じた後にアクセスしようとしてもエラー438になるケースがある
Dim rs As Object
Set rs = CreateObject("ADODB.Recordset")
' ... rs.Open後の処理 ...
rs.Close
rs.MoveFirst ' → 閉じたRecordsetへのアクセス → エラー438またはエラー3704
修正後のコード(ADODBの正しい実装パターン)
' ========================================
' ADODBの正しい実装パターン
' ========================================
Sub ReadFromAccessDB()
Dim conn As Object
Dim rs As Object
Dim ws As Worksheet
Dim row As Long
Set conn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
Set ws = ThisWorkbook.Sheets(1)
On Error GoTo ErrorHandler
' Connection を開く
conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=C:\data\sample.accdb;"
conn.Open
' Recordset を開く(ConnectionとRecordsetは別オブジェクト)
rs.Open "SELECT * FROM 売上テーブル", conn, 3, 1
' 引数: SQL, Connection, CursorType(3=Static), LockType(1=ReadOnly)
ws.Cells.Clear
row = 1
' フィールド名をヘッダーとして出力
Dim i As Integer
For i = 0 To rs.Fields.Count - 1
ws.Cells(1, i + 1).Value = rs.Fields(i).Name
Next i
row = 2
' レコードを1件ずつ読み込む
Do While Not rs.EOF
For i = 0 To rs.Fields.Count - 1
ws.Cells(row, i + 1).Value = rs.Fields(i).Value
Next i
rs.MoveNext ' ← MoveNextはRecordsetのメソッド(Connectionではない)
row = row + 1
Loop
MsgBox (row - 2) & " 件のデータを取得しました。", vbInformation
GoTo CleanUp
ErrorHandler:
MsgBox "エラーが発生しました。" & vbCrLf & _
"番号: " & Err.Number & vbCrLf & _
"内容: " & Err.Description, vbCritical
CleanUp:
' 状態を確認してから閉じる
If Not rs Is Nothing Then If rs.State = 1 Then rs.Close
If Not conn Is Nothing Then If conn.State = 1 Then conn.Close
Set rs = Nothing
Set conn = Nothing
Set ws = Nothing
End Sub
ADODBオブジェクトとメソッドの対応早見表
- ADODB.Connection が持つ主なメソッド:
Open、Close、Execute、BeginTrans、CommitTrans、RollbackTrans - ADODB.Recordset が持つ主なメソッド:
Open、Close、MoveFirst、MoveLast、MoveNext、MovePrevious、AddNew、Update、Delete、Find、Filter - ADODB.Command が持つ主なメソッド:
Execute、CreateParameter
原因5:グラフ・図形オブジェクトへのアクセスミス
Excelのグラフ操作では、Chart / ChartObject / ChartArea / PlotArea / Series など似た名前のオブジェクトが階層的に存在します。これらを混同してプロパティ・メソッドを呼び出すとエラー438が発生します。
よくある混同パターン
' ChartObjectとChartの混同
' NG:ChartObjectにはChartTitleプロパティは存在しない
Dim co As ChartObject
Set co = ActiveSheet.ChartObjects(1)
co.ChartTitle.Text = "売上推移" ' → エラー438
' OK:ChartObjectの.Chartプロパティを経由してChartにアクセスする
co.Chart.HasTitle = True
co.Chart.ChartTitle.Text = "売上推移"
' NG:SeriesCollectionのメソッドをChartに呼ぼうとしている
Dim cht As Chart
Set cht = ActiveSheet.ChartObjects(1).Chart
cht.MarkerStyle = xlMarkerStyleCircle ' → エラー438(ChartにはMarkerStyleがない)
' OK:Seriesオブジェクトを経由してアクセスする
Dim ser As Series
Set ser = cht.SeriesCollection(1)
ser.MarkerStyle = xlMarkerStyleCircle
グラフ操作の正しいオブジェクト階層
' ========================================
' グラフ操作の正しいオブジェクト階層
' ========================================
Sub SafeChartAccess()
Dim ws As Worksheet
Dim co As ChartObject ' シートに埋め込まれたグラフコンテナ
Dim cht As Chart ' グラフ本体
Dim ser As Series ' データ系列
Set ws = ThisWorkbook.Sheets(1)
' ChartObjectsコレクションからChartObjectを取得
If ws.ChartObjects.Count = 0 Then
MsgBox "グラフが存在しません。", vbExclamation
Exit Sub
End If
Set co = ws.ChartObjects(1) ' 1番目のグラフコンテナ
Set cht = co.Chart ' グラフ本体(ChartオブジェクトはChartObjectの中にある)
' グラフタイトルの設定
cht.HasTitle = True
cht.ChartTitle.Text = "月別売上推移"
' 軸ラベルの設定
With cht.Axes(xlCategory)
.HasTitle = True
.AxisTitle.Text = "月"
End With
With cht.Axes(xlValue)
.HasTitle = True
.AxisTitle.Text = "売上(万円)"
End With
' 1番目のデータ系列の設定
Set ser = cht.SeriesCollection(1)
ser.Name = "2024年売上"
ser.MarkerStyle = xlMarkerStyleCircle
ser.Format.Line.ForeColor.RGB = RGB(0, 112, 192)
Set ser = Nothing
Set cht = Nothing
Set co = Nothing
Set ws = Nothing
MsgBox "グラフの設定が完了しました。", vbInformation
End Sub
原因6:廃止・変更されたオブジェクト(InternetExplorerなど)
以前は広く使われていたが現在は廃止・動作不能になったオブジェクトを使おうとするとエラー438が発生します。代表例がInternet Explorer(IE)オブジェクトを使ったWebスクレイピングのコードです。IEはWindows 11・Microsoft 365環境では起動すらできなくなっているため、CreateObject("InternetExplorer.Application") が成功したとしても、以降の操作でエラー438が多発します。
廃止されたIEオブジェクトのコードと代替手段
' NG:IEオブジェクトを使った旧来のスクレイピング(現在は動作しない環境が多い)
Dim ie As Object
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = True
ie.Navigate "https://example.com"
Do While ie.Busy Or ie.ReadyState <> 4
DoEvents
Loop
' IEが廃止されている場合、以降の操作でエラー438が発生する
Dim doc As Object
Set doc = ie.Document
doc.getElementById("keyword").Value = "検索語" ' → エラー438の場合あり
' OK:XMLHTTPRequestを使ったHTTPリクエスト(IEが不要)
Sub FetchWebDataWithXHR()
Dim http As Object
Dim url As String
Dim resText As String
url = "https://api.example.com/data"
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", url, False
http.setRequestHeader "Content-Type", "application/json"
http.Send
If http.Status = 200 Then
resText = http.responseText
Debug.Print resText
' 取得したJSONやHTMLを解析して処理する
Else
MsgBox "HTTPリクエストが失敗しました。ステータス: " & http.Status, vbExclamation
End If
Set http = Nothing
End Sub
' OK:PowerShellを呼び出してWebスクレイピングを行う代替方法
Sub FetchWithPowerShell()
Dim cmd As String
Dim url As String
Dim outFile As String
url = "https://example.com"
outFile = ThisWorkbook.Path & "\response.txt"
' PowerShellのInvoke-WebRequestコマンドを使ってHTMLを取得
cmd = "powershell -Command ""Invoke-WebRequest -Uri '" & url & _
"' -UseBasicParsing | Select-Object -ExpandProperty Content | " & _
"Out-File -FilePath '" & outFile & "' -Encoding UTF8"""
Shell cmd, vbHide
Application.Wait Now + TimeValue("00:00:05") ' 完了を待つ
' 取得したテキストを読み込んで処理
If Dir(outFile) <> "" Then
Dim fileNo As Integer
Dim content As String
fileNo = FreeFile()
Open outFile For Input As #fileNo
Dim line As String
Do While Not EOF(fileNo)
Line Input #fileNo, line
content = content & line & vbCrLf
Loop
Close #fileNo
Debug.Print Left(content, 500) ' 先頭500文字を確認
End If
End Sub
原因7:自作クラスに存在しないメンバーへのアクセス
クラスモジュールを使って自作クラスを作成している場合、クラスに定義していないプロパティ・メソッドを外部から呼び出すとエラー438が発生します。また、Property Get は定義しているが Property Let を定義し忘れた場合に書き込もうとしてもエラー438になります。
エラーが起きるコード例
' クラスモジュール(clsPerson)の定義
' ---- clsPerson の内容 ----
Private m_Name As String
Private m_Age As Long
Public Property Get Name() As String
Name = m_Name
End Property
Public Property Let Name(val As String)
m_Name = val
End Property
Public Property Get Age() As Long
Age = m_Age
End Property
' Property Let Age は定義していない(読み取り専用のつもり)
' ---- ここまで ----
' 呼び出し側
Dim p As clsPerson
Set p = New clsPerson
p.Name = "山田太郎" ' OK(Property Letあり)
p.Age = 30 ' → エラー438(Property LetがないのでAgeへの書き込みは不可)
Debug.Print p.Email ' → エラー438(Emailプロパティは定義していない)
修正後のコード
' ========================================
' クラスモジュール(clsPerson)の正しい実装
' ========================================
' ---- clsPerson の内容 ----
Option Explicit
Private m_Name As String
Private m_Age As Long
Private m_Email As String
' Name:読み書き可能
Public Property Get Name() As String
Name = m_Name
End Property
Public Property Let Name(val As String)
m_Name = val
End Property
' Age:読み取り専用(外部から書き込み不可)
Public Property Get Age() As Long
Age = m_Age
End Property
' ※ Property Let Ageを定義しないことで意図的に読み取り専用にしている
' 外部からAge = 30 のように書くとエラー438になる(意図どおり)
' Email:読み書き可能
Public Property Get Email() As String
Email = m_Email
End Property
Public Property Let Email(val As String)
m_Email = val
End Property
' 初期化メソッド(コンストラクタ代わり)
Public Sub Initialize(name As String, age As Long, _
Optional email As String = "")
m_Name = name
m_Age = age
m_Email = email
End Sub
' 文字列表現を返すメソッド
Public Function ToString() As String
ToString = m_Name & "(" & m_Age & "歳)" & _
IIf(Len(m_Email) > 0, " <" & m_Email & ">", "")
End Function
' ---- ここまで ----
' 呼び出し側
Sub UseClsPerson()
Dim p As clsPerson
Set p = New clsPerson
p.Initialize "山田太郎", 30, "[email protected]"
Debug.Print p.Name ' → "山田太郎"
Debug.Print p.Age ' → 30(読み取りはOK)
Debug.Print p.Email ' → "[email protected]"
Debug.Print p.ToString ' → "山田太郎(30歳) <[email protected]>"
' p.Age = 31 ← コメントアウト:読み取り専用なのでエラー438になる(意図どおり)
Set p = Nothing
End Sub
オブジェクトブラウザを使った正しいプロパティ・メソッドの調べ方
エラー438を根本から防ぐには、オブジェクトブラウザを活用してオブジェクトが持つプロパティ・メソッドを正確に確認する習慣が重要です。
オブジェクトブラウザの開き方と使い方
- VBAエディタで F2キー を押す(またはメニューの「表示」→「オブジェクトブラウザ」)
- 左上のドロップダウンから調べたいライブラリ(例:
Excel、ADODB)を選択する - 左のクラス一覧から調べたいクラス(例:
Range、Worksheet)を選択する - 右のメンバー一覧に、そのクラスが持つすべてのプロパティ・メソッド・イベントが表示される
- メンバーを選択すると画面下部に説明・引数・戻り値の型が表示される
' オブジェクトブラウザでの確認例:
' 1. F2キーでオブジェクトブラウザを開く
' 2. ライブラリ選択:「Excel」
' 3. クラス選択:「Range」
' 4. メンバー一覧で「Value」を探すと:
' Property Value As Variant
' という定義が確認できる
' 5. 「Values」を検索すると見つからない
' → 「Value」が正しく「Values」はエラーになることが事前に確認できる
オブジェクトの型をコード内で動的に確認する方法
' ========================================
' オブジェクトの型とメンバーをコード内で確認するデバッグ用プロシージャ
' ========================================
Sub InspectObject(obj As Object)
If obj Is Nothing Then
Debug.Print "オブジェクトはNothingです"
Exit Sub
End If
Debug.Print "=============================="
Debug.Print "TypeName : " & TypeName(obj)
Debug.Print "VarType : " & VarType(obj)
' プロパティへのアクセスチェック例
On Error Resume Next
Dim testVal As Variant
' よく使うプロパティが存在するかを動的に確認
testVal = CallByName(obj, "Value", VbGet)
If Err.Number = 0 Then Debug.Print "Value : サポートあり"
Err.Clear
testVal = CallByName(obj, "Name", VbGet)
If Err.Number = 0 Then Debug.Print "Name : サポートあり"
Err.Clear
testVal = CallByName(obj, "Address", VbGet)
If Err.Number = 0 Then Debug.Print "Address : サポートあり"
Err.Clear
On Error GoTo 0
Debug.Print "=============================="
End Sub
' 使用例
Sub CheckObjectType()
InspectObject ActiveSheet.Range("A1") ' Range型のメンバーを確認
InspectObject ActiveSheet ' Worksheet型のメンバーを確認
InspectObject ActiveSheet.ChartObjects(1) ' ChartObject型のメンバーを確認
End Sub
デバッグ手順:エラー438の原因を素早く特定する
ステップ1:エラー行でどのオブジェクトの何を呼んでいるかを確認する
エラーダイアログで「デバッグ」ボタンを押してエラー行を特定します。その行で「どのオブジェクト変数に対して」「どのプロパティ・メソッドを」呼んでいるかを確認してください。
ステップ2:イミディエイトウィンドウでTypeNameを確認する
' Ctrl+G でイミディエイトウィンドウを開き、以下を入力してEnter
' ?TypeName(変数名)
' 例:ws変数の型を確認
?TypeName(ws)
' → "Worksheet" なら正しい
' → "Chart" ならChartシートが取得されている(CellsなどはChartにはない)
' → "Nothing" ならエラー91が発生するはず
' Selectionの型を確認
?TypeName(Selection)
' → "Range" ならセルが選択されている
' → "ChartArea" などならグラフ系オブジェクトが選択されている
ステップ3:プロパティ名のスペルをオブジェクトブラウザで確認する
エラー行のプロパティ名・メソッド名をF2キーのオブジェクトブラウザで検索してください。見つからない場合はスペルミスか、そのオブジェクト型には存在しないメンバーです。
ステップ4:On Error Resume Nextで438かどうかを絞り込む
' エラー438が特定の行で起きているかを確認するデバッグコード
On Error Resume Next
Dim testResult As Variant
testResult = ActiveSheet.Range("A1").Values ' 疑わしいコード
If Err.Number = 438 Then
Debug.Print "エラー438確認:このプロパティはサポートされていません"
Debug.Print "正しいプロパティ名: Value(Valuesではない)"
Err.Clear
End If
On Error GoTo 0
エラーハンドリングテンプレート
' ========================================
' エラー438対応エラーハンドリングテンプレート
' ========================================
Sub MainWithError438Handling()
Dim ws As Worksheet
Dim rng As Range
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
On Error GoTo ErrorHandler
' オブジェクトを具体的な型で宣言・取得することでエラー438を予防する
Set ws = ThisWorkbook.Sheets("データ")
Set rng = ws.Range("A1:A100")
' ===== メイン処理 =====
rng.Value = "処理済"
rng.Font.Bold = True
' =====================
MsgBox "処理完了", vbInformation
GoTo CleanUp
ErrorHandler:
Dim msg As String
Select Case Err.Number
Case 438
msg = "プロパティまたはメソッドがサポートされていません(エラー438)。" & vbCrLf & vbCrLf & _
"確認してください:" & vbCrLf & _
"・プロパティ名・メソッド名のスペルが正しいか(F2でオブジェクトブラウザ確認)" & vbCrLf & _
"・取得したオブジェクトの型が意図したものか(TypeNameで確認)" & vbCrLf & _
"・Excelバージョンがその機能に対応しているか(Application.Versionで確認)" & vbCrLf & _
"・廃止されたオブジェクト(IEなど)を使っていないか"
Case 91
msg = "オブジェクト変数が設定されていません(エラー91)。" & vbCrLf & _
"Setキーワードでオブジェクトを代入してください。"
Case 9
msg = "添字が有効範囲にありません(エラー9)。" & vbCrLf & _
"シート名・配列の添字を確認してください。"
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
Set rng = Nothing
Set ws = Nothing
End Sub
エラー438 原因チェックリスト
エラー438が発生したとき、以下のリストを上から順番に確認してください。
- エラー行のプロパティ名・メソッド名をF2キーのオブジェクトブラウザで検索して正確に存在することを確認したか
- 単数形・複数形の違いや末尾の s の有無(Value vs Values、Color vs Colors、Row vs Rowsなど)を確認したか
TypeName(変数名)でオブジェクトの型が意図したものになっているかイミディエイトウィンドウで確認したか- 変数を
Object型やVariant型ではなく具体的な型(Worksheet、Range など)で宣言してIntelliSenseを有効にしているか - Selection を使っている場合、その時点でセル(Range)が選択されているか、グラフや図形が選択されていないか確認したか
- ActiveSheet を使っている場合、通常のワークシートがアクティブか、グラフシート(Chart)ではないかを確認したか
- ChartObjectとChart を混同していないか(ChartTitleなどはChart経由でアクセスする)
- 使用している機能が現在のExcelバージョンでサポートされているか(
Application.Versionで確認) - IE(InternetExplorer)オブジェクトを使ったコードをそのまま使っていないか(Windows 11・Microsoft 365環境では動作しない)
- ADODBを使っている場合、ConnectionとRecordsetのメソッドを混同していないか
- 自作クラスに対して定義していないプロパティ・メソッドを呼び出していないか
- 読み取り専用プロパティ(
Property Letが未定義)に書き込もうとしていないか
まとめ
実行時エラー’438’「オブジェクトはこのプロパティまたはメソッドをサポートしていません」は、呼び出したプロパティ名・メソッド名がそのオブジェクトに存在しないときに発生します。エラー91(Nothingへのアクセス)と並んでVBAで最も遭遇しやすいオブジェクト関連エラーです。本記事の要点をまとめると次のとおりです。
- スペルミス対策:変数を
ObjectではなくWorksheet・Rangeなどの具体的な型で宣言してIntelliSenseを活用する。F2キーのオブジェクトブラウザで正確な名前を確認する - オブジェクト型の確認:
TypeName()でオブジェクトの実際の型を確認し、Selection・ActiveSheetなどの状態依存オブジェクトは使用前に型チェックを入れる - バージョン対応:
Application.VersionでExcelのバージョンを確認し、新機能を使うときはバージョン分岐を入れる - グラフ操作:ChartObjectとChartを混同しない。ChartTitle・SeriesなどはChart経由でアクセスする
- 廃止オブジェクト:IEオブジェクトなど廃止されたオブジェクトはXMLHTTPRequestやPowerShellへの移行を検討する
- ADODBの使い方:ConnectionとRecordsetのメソッドを正確に区別する。MoveNextなどはRecordsetのメソッド
- 自作クラス:Property LetとProperty Getの両方を定義しないと書き込み時にエラー438になる
エラー438は、コードを書く時点での型指定と入力補完の活用によって大幅に予防できます。As Object や As Variant で宣言する習慣から、具体的な型名で宣言する習慣に切り替えるだけで、エラー438の発生件数を劇的に減らすことができます。