エラーの説明
Excelマクロを実行中に、ダイアログボックスが突然表示されてすべての処理が中断されます:
Run-time error '1004':
Application-defined or object-defined error
マクロは完全に停止します。デバッグをクリックすると、VBAが問題のある行を黄色でハイライトします — 通常はRange、Cells、ActiveSheet、または.Selectの呼び出しが関係しています。
エラー1004はExcelの汎用ランタイムエラーです。十数通りの意味を持つ可能性があるため、原因の特定が非常に厄介です。しかし、ほとんどのケースは5つのパターンに分類されます。パターンを認識し、修正を適用すれば完了です。
根本原因
.Selectまたは.Activateを使用する際に、アクティブでないシートの範囲を参照している- 現在アクティブなブックやシートとは異なるブックまたはシートの範囲で
.Selectを呼び出している - 保護されたシートへの書き込み
- 無効な範囲アドレスの使用 — 空文字列、1,048,576を超える行番号、または16,384を超える列番号
- ブックに存在しない名前付き範囲へのアクセス
- 貼り付けサイズが一致しない結合セル領域への貼り付け
- 空または不一致の範囲での
AutoFill、Sort、PasteSpecialの呼び出し
修正1 — .SelectとActivateの使用をやめる(最も一般的な修正)
マクロレコーダーの出力が最大の原因です。マクロを記録すると、Excelは次のようなコードを生成します:
Sheets("Data").Select
Range("A1").Select
Selection.Value = "Hello"
これは実行時に"Data"がアクティブシートである場合にのみ機能します。別のシートや別のブックがアクティブになった瞬間、1004エラーが発生します。シートを直接参照するように書き直してください:
' 修正前(壊れやすい)
Sheets("Data").Select
Range("A1").Select
Selection.Value = "Hello"
' 修正後(信頼性が高い)
Sheets("Data").Range("A1").Value = "Hello"
シートをアクティブにせずに書き込む完全なパターンを以下に示します:
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Data")
ws.Range("A1").Value = "Hello"
ws.Range("B2:B10").ClearContents
ws.Cells(3, 1).Value = 42
修正2 — シートの保護を確認する
保護されたシートへの書き込みを試みた瞬間、エラー1004が発生します — 猶予はありません。書き込む前に保護を解除し、完了後に再度保護してください:
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Report")
' 書き込む前に保護を解除(パスワードが設定されている場合は指定)
ws.Unprotect Password:="yourpassword"
ws.Range("C5").Value = "Updated"
' 完了後に再度保護
ws.Protect Password:="yourpassword"
パスワードがわからず、クラッシュさせずにスキップしたい場合:
If Not ws.ProtectContents Then
ws.Range("C5").Value = "Updated"
Else
MsgBox "シートが保護されています。書き込めません。"
End If
修正3 — 使用前に範囲参照を検証する
空文字列や範囲外の行番号は即座に1004を引き起こします。Excelの行数の上限は1,048,576です — それを超える値を渡すとクラッシュします。入力値を検証してください:
' 問題あり:rowNum が 0 または負の値になる可能性がある
ws.Cells(rowNum, 1).Value = "data"
' 良い例:使用前に検証する
If rowNum >= 1 And rowNum <= ws.Rows.Count Then
ws.Cells(rowNum, 1).Value = "data"
Else
MsgBox "行番号が範囲外です:" & rowNum
End If
名前付き範囲にも同様の処理が必要です。存在を前提にせず、最初に確認してください:
Function NamedRangeExists(wb As Workbook, nameStr As String) As Boolean
Dim nm As Name
On Error Resume Next
Set nm = wb.Names(nameStr)
NamedRangeExists = (Not nm Is Nothing)
On Error GoTo 0
End Function
' 使用例
If NamedRangeExists(ThisWorkbook, "SalesData") Then
ThisWorkbook.Names("SalesData").RefersToRange.Value = 0
End If
修正4 — PasteSpecialとAutoFillのエラーを修正する
クリップボードが空の場合や、互換性のない領域(結合セルは一般的な落とし穴)に貼り付けようとする場合、PasteSpecialは失敗します。形式の競合を避けるため、常に最初にコピーしてから値のみを貼り付けてください:
' コピー元をコピー
wsSource.Range("A1:A10").Copy
' 宛先に値のみを貼り付け(形式の競合を回避)
wsDest.Range("B1").PasteSpecial Paste:=xlPasteValues
' 貼り付け後にクリップボードをクリア
Application.CutCopyMode = False
AutoFillにはより厳しい要件があります:宛先範囲はソースと同じセルから始まる必要があります。わずかでもずれると1004エラーが発生します:
Dim srcRange As Range
Dim fillRange As Range
Set srcRange = ws.Range("A1:A2")
' 宛先はソースと同じセルから始まる必要があります
Set fillRange = ws.Range("A1:A10")
srcRange.AutoFill Destination:=fillRange, Type:=xlFillDefault
修正5 — ブックが開いていないまたは誤ったブック参照
開いていないブックを名前で参照すると、Excelは1004エラーをスローします。マクロが含まれているファイルを参照する場合はThisWorkbookを使用してください — 他に何が開いていても常に利用可能です:
' リスクあり:ブックが開いており、名前が正確であることを前提としている
Workbooks("Report_2024.xlsx").Sheets("Data").Range("A1").Value = 1
' 安全:このマクロが含まれているブックを参照
ThisWorkbook.Sheets("Data").Range("A1").Value = 1
' または特定の開いているブックをループで検索
Dim wb As Workbook
For Each wb In Application.Workbooks
If wb.Name = "Report_2024.xlsx" Then
wb.Sheets("Data").Range("A1").Value = 1
Exit For
End If
Next wb
デバッグ:正確な行を特定する
エラーダイアログが表示されたら、デバッグをクリックします。VBAが問題のある行を黄色でハイライトします。そこから:
- 変数の上にカーソルを合わせると、ツールチップに現在の値が表示されます
- イミディエイトウィンドウ(
Ctrl+G)を開いて? variableNameと入力して値を確認します - エラー行の直前に
Stopステートメントを追加して実行を一時停止し、状態を確認します
' 一時的なデバッグ用 — 本番前に削除すること
Stop ' ここで実行が一時停止します
ws.Range(rangeAddress).Value = newValue
予防策
- 記録したマクロのコードをすべてリファクタリングする — リリース前にすべての
.Selectと.Activateを取り除く - 範囲参照には必ずシート変数を付ける:
Range(...)ではなくws.Range(...) - 本番マクロには
On Error GoToハンドラーを追加する — 意味のあるエラーメッセージを表示するため - データを書き込むマクロの開始時にシートの保護を解除し、終了時に再度保護する
- 動的な値を検証する(行番号、範囲文字列)、範囲呼び出しに渡す前に
確認方法
VBAエディタでF5を押して最初から実行します。ダイアログボックスが表示されなければ成功です。次にエッジケースをテストしてください:
- 空のシートで実行する
- 保護されたシートがアクティブな状態で実行する
- 無効な入力を渡す — 行番号0、空白の範囲文字列
- 最終バージョンをリリースする前に
Stopやデバッグ用ステートメントをすべて削除する

