엑셀 매크로를 실행할 때 다음 메시지가 나타날 수 있습니다.
런타임 오류 '91':
개체 변수 또는 With 블록 변수가 설정되지 않았습니다.
이 오류는 VBA가 워크시트, 셀 범위, 통합 문서 같은 객체를 사용하려 했지만 해당 변수가 현재 유효한 객체를 가리키지 않을 때 발생합니다.
가장 흔한 원인은 객체 변수를 선언만 하고 Set으로 할당하지
않은 경우와, Range.Find가 검색 결과를 찾지 못해
Nothing을 반환한 경우입니다.
이 글은 Microsoft의 VBA 오류 91, Set 문과 Excel Range.Find 공식 문서를 기준으로 작성했습니다. 예제 코드는 실제 파일 구조에 맞게 시트 이름과 검색 범위를 변경해야 합니다.
![]() |
| 디버그에서 멈춘 코드의 객체 변수가 Nothing인지 확인하고 Set 할당과 Find 결과 검사를 추가합니다. |
오류 창이 나타나면 먼저 ‘디버그’를 누르세요
오류 창에서 종료를 바로 누르면 어느 코드에서 문제가 발생했는지 확인하기 어렵습니다. 먼저 디버그를 선택하세요.
VBA 편집기가 열리면서 오류가 발생한 코드가 노란색으로 표시됩니다. 노란색 줄에서 마침표 왼쪽에 있는 객체 변수를 확인하면 원인을 좁힐 수 있습니다.
ws.Cells(2, 1).Value에서 오류가 발생했다면
ws를 확인합니다.foundCell.Row에서 오류가 발생했다면
foundCell을 확인합니다.wb.Worksheets(1).Name에서 오류가 발생했다면
wb를 확인합니다.
오류가 발생한 줄 전체를 무작정 바꾸기보다, 속성이나 메서드를 호출하기 직전의 객체가 올바르게 설정됐는지 확인해야 합니다.
원인 1: 객체 변수를 선언만 하고 Set으로 할당하지 않음
아래 코드는 ws를 Worksheet 객체 변수로 선언했지만 실제
워크시트를 할당하지 않았습니다.
오류가 발생하는 코드
Sub CheckLastRow()
Dim ws As Worksheet
Dim lastRow As Long
lastRow = ws.Cells( _
ws.Rows.Count, "A" _
).End(xlUp).Row
MsgBox lastRow
End Sub
ws는 선언됐지만 어떤 워크시트도 가리키지 않습니다. 따라서
ws.Cells를 사용하는 줄에서 오류 91이 발생합니다.
Set으로 워크시트를 할당한 코드
Sub CheckLastRow()
Dim ws As Worksheet
Dim lastRow As Long
Set ws = ThisWorkbook.Worksheets("Data")
lastRow = ws.Cells( _
ws.Rows.Count, "A" _
).End(xlUp).Row
MsgBox lastRow
End Sub
실제 시트 이름이 Data가 아니라면 코드의
"Data" 부분을 Excel 아래쪽 시트 탭에 표시되는 이름으로
변경해야 합니다.
시트 이름이 잘못되면 오류 91이 아니라 런타임 오류 9가 나타날 수 있습니다. 띄어쓰기와 특수문자까지 실제 시트 이름과 정확히 일치하는지 확인하세요.
원인 2: Find가 검색 결과를 찾지 못함
Range.Find는 검색 결과가 있으면 해당 셀을 Range 객체로
반환하지만, 결과가 없으면 Nothing을 반환합니다.
다음처럼 검색 결과에 바로 .Row를 연결하면 찾는 값이 없을
때 오류 91이 발생할 수 있습니다.
검색 결과를 바로 사용하는 위험한 코드
totalRow = ws.Columns("A").Find( _
What:="총계" _
).Row
A열에 정확히 총계라는 값이 없다면 Find 결과는
Nothing입니다. 이 상태에서는 .Row를 사용할
수 없습니다.
검색 결과를 먼저 확인하는 코드
Dim foundCell As Range
Set foundCell = ws.Columns("A").Find( _
What:="총계", _
After:=ws.Cells(ws.Rows.Count, "A"), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False _
)
If foundCell Is Nothing Then
MsgBox "'총계'를 찾지 못했습니다.", _
vbInformation
Exit Sub
End If
MsgBox "총계가 있는 행: " & foundCell.Row
핵심은 Find의 결과를 Range 변수에 먼저 저장하고, 다음 조건으로 결과가 존재하는지 확인하는 것입니다.
If foundCell Is Nothing Then
결과가 없을 때는 메시지를 표시하거나 해당 작업을 건너뛰도록 처리합니다.
결과가 있다는 사실을 확인한 뒤에만 .Row,
.Value 같은 속성을 사용하세요.
Find의 검색 조건을 생략하지 않는 이유
Excel의 찾기 창에서 선택한 검색 범위나 검색 대상 설정은 다음 Find 실행에도 영향을 줄 수 있습니다. 코드가 실행될 때마다 같은 조건으로 검색하려면 다음 인수를 가능한 한 명시하는 것이 좋습니다.
-
LookIn:=xlValues: 셀에 표시되는 값을 기준으로 검색 -
LookAt:=xlWhole: 셀 전체 내용이 검색어와 같을 때만 일치 -
SearchOrder:=xlByRows: 행을 기준으로 검색 -
SearchDirection:=xlNext: 다음 방향으로 검색 -
MatchCase:=False: 영문 대소문자를 구분하지 않음 -
SearchFormat:=False: 특정 셀 서식을 검색 조건으로 사용하지 않음
검색어가 포함된 셀도 찾으려면 LookAt:=xlWhole을
LookAt:=xlPart로 변경할 수 있습니다.
셀 내용이
총계일 때 두 설정 모두 찾을 수 있습니다.셀 내용이
상반기 총계일 때
xlWhole은 찾지 못하고 xlPart는 찾을 수
있습니다.
원인 3: With 블록에서 사용하는 객체가 Nothing 상태임
오류 메시지에 표시되는 ‘With 블록 변수가 설정되지 않았습니다’는
With 뒤에 사용한 객체가 유효하지 않은 경우에도 나타날 수
있습니다.
오류가 발생하는 With 코드
Sub WriteResult()
Dim targetCell As Range
With targetCell
.Value2 = "완료"
.Font.Bold = True
End With
End Sub
targetCell을 선언했지만 셀을 할당하지 않았으므로
.Value2에서 오류 91이 발생합니다.
객체를 할당한 뒤 사용하는 코드
Sub WriteResult()
Dim ws As Worksheet
Dim targetCell As Range
Set ws = ThisWorkbook.Worksheets("Data")
Set targetCell = ws.Range("B2")
With targetCell
.Value2 = "완료"
.Font.Bold = True
End With
End Sub
With 블록 자체를 삭제하는 것이 해결책은 아닙니다. With가 사용하는 객체가 어느 줄에서 할당돼야 하는지 확인해야 합니다.
원인 4: 함수가 객체를 찾지 못하고 Nothing을 반환함
별도의 함수에서 Range, Worksheet 또는 Workbook 객체를 반환하도록
만들었더라도 조건에 맞는 객체를 찾지 못하면 반환값이
Nothing일 수 있습니다.
호출한 쪽에서는 함수가 항상 객체를 돌려줄 것이라고 가정하지 말고 결과를 확인해야 합니다.
Dim targetCell As Range
Set targetCell = FindTotalCell( _
ThisWorkbook.Worksheets("Data") _
)
If targetCell Is Nothing Then
MsgBox "총계 셀을 찾지 못했습니다.", _
vbInformation
Exit Sub
End If
MsgBox targetCell.Address
객체를 반환하는 함수의 결과에도 동일하게
Is Nothing 검사를 적용할 수 있습니다.
총계 셀을 안전하게 찾는 전체 예제
아래 코드는 이름이 Data인 워크시트의 A열에서
총계라는 값을 찾습니다. 검색 결과가 없으면 오류를 발생시키지
않고 안내 메시지를 표시합니다.
이 코드는 셀의 내용을 수정하지 않고 검색된 행 번호만 메시지로 보여줍니다.
Option Explicit
Private Const SHEET_NAME As String = "Data"
Private Const SEARCH_COLUMN As String = "A"
Private Const SEARCH_TEXT As String = "총계"
Public Sub FindTotalRowSafely()
Dim ws As Worksheet
Dim foundCell As Range
On Error GoTo ErrorHandler
Set ws = ThisWorkbook.Worksheets(SHEET_NAME)
Set foundCell = ws.Columns(SEARCH_COLUMN).Find( _
What:=SEARCH_TEXT, _
After:=ws.Cells(ws.Rows.Count, SEARCH_COLUMN), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False _
)
If foundCell Is Nothing Then
MsgBox _
"'" & SEARCH_TEXT & _
"'을(를) " & SEARCH_COLUMN & _
"열에서 찾지 못했습니다.", _
vbInformation
Exit Sub
End If
MsgBox _
"'" & SEARCH_TEXT & _
"'이(가) 있는 행: " & foundCell.Row, _
vbInformation
Exit Sub
ErrorHandler:
Select Case Err.Number
Case 9
MsgBox _
"'" & SHEET_NAME & _
"' 워크시트를 찾지 못했습니다." & vbCrLf & _
"코드의 SHEET_NAME을 확인하세요.", _
vbExclamation
Case 91
MsgBox _
"사용하려는 객체가 설정되지 않았습니다." & vbCrLf & _
"Set 할당과 Find 결과를 확인하세요.", _
vbExclamation
Case Else
MsgBox _
"오류 번호: " & Err.Number & vbCrLf & _
"오류 내용: " & Err.Description, _
vbExclamation
End Select
End Sub
전체 코드에서 직접 바꿀 부분
워크시트 이름
Private Const SHEET_NAME As String = "Data"
실제 시트 탭 이름이 매출이라면
"Data"를 "매출"로 변경합니다.
검색할 열
Private Const SEARCH_COLUMN As String = "A"
검색할 값이 C열에 있다면 "A"를
"C"로 변경합니다.
검색할 글자
Private Const SEARCH_TEXT As String = "총계"
실제로 찾을 값이 합계라면
"총계"를 "합계"로 변경합니다.
On Error Resume Next로 오류를 숨기지 마세요
오류 91이 나타난다는 이유로 코드 전체에 다음 문장을 추가하면 화면에는 오류가 표시되지 않을 수 있습니다.
On Error Resume Next
하지만 객체가 설정되지 않은 원인은 그대로 남습니다. 이후 코드가 실행되지 않거나 잘못된 결과가 저장돼도 원인을 찾기 어려워질 수 있습니다.
Find 결과는 Is Nothing으로 확인하고, 예상할 수 없는 오류는
On Error GoTo ErrorHandler처럼 별도의 오류 처리 구간에서
표시하는 편이 낫습니다.
Option Explicit로 변수 이름 실수 줄이기
코드 모듈의 맨 위에 다음 문장을 넣으면 선언하지 않은 변수 이름을 사용할 때 컴파일 단계에서 확인할 수 있습니다.
Option Explicit
VBA 편집기에서 디버그 → VBAProject 컴파일을 실행하면 변수 이름, 구문과 선언 문제를 매크로 실행 전에 확인하는 데 도움이 됩니다.
오류가 발생한 줄에서 이 순서로 확인하세요
Dim으로 선언만 되고
Set되지 않았는지
Nothing을 반환할 수 있는지
If 객체 Is Nothing Then 검사가 있는지
On Error Resume Next가 실제 오류를 숨기고 있지 않은지
런타임 오류 91은 오류가 표시된 속성이나 메서드 자체보다, 그 앞에 있는 객체 변수가 유효한 객체를 가리키고 있는지를 확인하는 것이 핵심입니다.

댓글 쓰기