🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA Check If Sheet Exists in Excel — One Function, and the Three Ways It Goes Wrong

|

VBA Check If Sheet Exists in Excel — One Function, and the Three Ways It Goes Wrong

TL;DR — There is no Sheets.Exists. Write one function, put it in every project, and stop improvising: try to Set the sheet with error handling switched off for one line, then check whether the variable is Nothing. Get three details right and it never lies: ask a specific workbook, not whatever happens to be active; search Sheets, not Worksheets, because a chart sheet can already hold the name; and pass the name as a String, because a Variant holding a number is read as a position. Remember that hidden sheets exist too — "exists" is not "visible".

Function SheetExists(ByVal sheetName As String, Optional wb As Workbook) As Boolean
    Dim sh As Object
    If wb Is Nothing Then Set wb = ThisWorkbook
    On Error Resume Next
    Set sh = wb.Sheets(sheetName)
    On Error GoTo 0
    SheetExists = Not sh Is Nothing
End Function

This is the third of a three-part cluster on a sheet's identity. The tab name is a label the user owns. Rename changes that label, hide takes the tab off screen without taking the sheet out of reach, and exists, covered here, is the check you run before trusting a label. Any code that finds a sheet by a name a user could have changed should ask this question first.

What you'll learn

  • The mental model: existence is a question about one name in one workbook
  • The function, and why each of its lines is there
  • Three ways the common versions give the wrong answer
  • Loop, On Error, or Evaluate: which approach to use when
  • The patterns that depend on it: get-or-create, delete-if-exists, unique names
  • Checking a sheet in a workbook that is closed

The mental model: one name, one workbook, one namespace

"Does the sheet exist?" is always shorthand for a narrower question: does this workbook contain a sheet of any kind whose name matches this text, ignoring case? Each part of that sentence is a place where a check can go wrong. This workbook — not the active one by accident. A sheet of any kind — worksheets and chart sheets share one set of names. Ignoring case — SALES and Sales are the same name to Excel.

And a sheet that exists may not be on screen. Hidden and very hidden sheets are still in the collection, so the check finds them — which is exactly right when you are about to add a sheet with that name, because Excel would refuse the duplicate even though the user cannot see it.

The function, line by line

The version above does four things, and each one matters:

  1. Dim sh As Object — Object, not Worksheet, so a chart sheet can be assigned without a type mismatch.
  2. If wb Is Nothing Then Set wb = ThisWorkbook — a default you chose on purpose, instead of the implicit ActiveWorkbook an unqualified Sheets would use.
  3. On Error Resume Next ... On Error GoTo 0 — errors are ignored for exactly one line. The lookup raises error 9 when the name is missing, which is the answer we want; any other error elsewhere stays visible. The On Error guide explains why the switch must always be turned back off.
  4. SheetExists = Not sh Is Nothing — if the lookup failed, sh was never set and is still Nothing.

Use it wherever a name comes from outside your code — a cell, a user, a file name:

If SheetExists("Summary") Then
    ThisWorkbook.Sheets("Summary").Range("A1").Value = Date
Else
    MsgBox "The Summary sheet is missing."
End If

Debug.Print SheetExists("Rates", Workbooks("Prices.xlsx"))   ' ask another open workbook

Three ways the common versions give the wrong answer

1. Asking the wrong workbook. Many snippets call Sheets(name) with no workbook in front. That searches whatever workbook is active when the line runs — which is not the one you meant as soon as your macro has opened a second file. The check says "missing", the next line adds a sheet to the wrong workbook, and nothing errors. Always pass or default the workbook explicitly, as the function does.

2. Searching Worksheets instead of Sheets. Worksheets only contains worksheets; Sheets also contains chart sheets. Names are unique across both. So if a chart sheet is called Summary, a check against Worksheets says the name is free, and ws.Name = "Summary" then fails with error 1004. For "can I use this name?" the only correct collection is Sheets.

3. Passing a number by accident. Sheets(3) means the third sheet; Sheets("3") means the sheet called 3. If the name arrives in a Variant — from a cell, for example — and the cell holds the number 3, the lookup goes by position and finds whatever sheet is third. The check says "exists" for a sheet that has nothing to do with the name. Declaring the parameter ByVal sheetName As String forces the conversion to text before the lookup, which is why the signature matters.

Loop, On Error, or Evaluate

You will see three approaches. Here is how they compare:

Approach How Verdict
On Error + Set try the lookup, check for Nothing default — one lookup, exact Excel semantics
Loop + StrComp compare each name, case-insensitively clear; use it when you match a pattern, not a name
Evaluate("ISREF(...)") build a formula reference and test it avoid — breaks on apostrophes and chart sheets

The loop is the right tool when "exists" really means "any sheet whose name starts with 2026":

Function FirstSheetLike(wb As Workbook, ByVal pattern As String) As Object
    Dim sh As Object
    For Each sh In wb.Sheets
        If LCase$(sh.Name) Like LCase$(pattern) Then
            Set FirstSheetLike = sh
            Exit Function
        End If
    Next sh
End Function

' Set sh = FirstSheetLike(ThisWorkbook, "2026-*")  ' Nothing if none matches

The Evaluate trick — Evaluate("ISREF('" & name & "'!A1)") — looks clever and fails in quiet ways: a name containing an apostrophe breaks the formula unless you double it, a chart sheet has no A1 and returns False, and the formula is evaluated against the active workbook. It saves two lines and costs you three bugs.

The patterns built on it

Almost every use of the check is one of three patterns, and each has its own guide:

' Get or create: reuse the sheet if it is there, otherwise add it
If SheetExists("Log") Then
    Set ws = ThisWorkbook.Worksheets("Log")
Else
    Set ws = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
    ws.Name = "Log"
End If

' Delete if exists: no error 9 when it is already gone
If SheetExists("Temp") Then
    Application.DisplayAlerts = False
    ThisWorkbook.Sheets("Temp").Delete
    Application.DisplayAlerts = True
End If

The Add Sheet guide covers the first in full, the Delete Sheet guide the second, including the last-visible-sheet rule. The third is generating a free name — Report (2), Report (3) — which the Rename Sheet guide builds on top of SheetExists.

The judgment call: check names, do not rely on them

The check exists because names are fragile. It makes code that has to use a name — sheets the user creates, names typed into a cell, files from outside — safe. It is not a reason to keep finding your own sheets by name. For sheets your tool owns, use the CodeName and there is nothing to check. My rule: if a name came from a person, check it; if the sheet came from you, do not look it up by name at all. And for a workbook that is closed, there is no shortcut worth trusting: open it read-only, check with the same function, and close it.

How ExcelMaster helps

Existence bugs rarely look like existence bugs. They look like a sheet added to the wrong workbook, a rename that fails because a chart sheet already had the name, or a macro that writes a month's figures into sheet number 3 because a cell held a number instead of text.

ExcelMaster lets you describe the job — "for each region in column A, reuse its sheet if it exists or create it" — and writes the check against the right workbook and the right collection, with the name passed as text, so the get-or-create logic does what it says.

Frequently asked questions

How do I check if a sheet exists in VBA?

There is no built-in method, so use a small function: switch error handling off, try Set sh = wb.Sheets(name), switch it back on, and return Not sh Is Nothing. It finds worksheets and chart sheets, visible or hidden, and ignores case the way Excel does.

How do I check if a sheet exists in another workbook?

Pass that workbook to the function, for example SheetExists("Rates", Workbooks("Prices.xlsx")). The workbook has to be open. If it is closed, open it read-only, run the check, and close it again.

Is the sheet name check case-sensitive?

No. Excel treats Sales, SALES and sales as the same name, so the lookup through Sheets(name) is not case-sensitive. If you loop and compare names yourself, use StrComp(a, b, vbTextCompare) or compare LCase$ values to get the same result.

Why does my check say a sheet does not exist when I cannot add it?

Usually because the check searched Worksheets and the name is used by a chart sheet, which only appears in Sheets. Names must be unique across both, so check against Sheets. A hidden sheet can also hold the name; the check finds it, but you cannot see it in the tab strip.

Does a hidden sheet count as existing?

Yes. Hidden and very hidden sheets are still in the Sheets collection, so the check returns True for them. If you need to know whether the user can see it, test sh.Visible = xlSheetVisible after the check.

Tested in

Tested in: Excel 365 (Windows 11), VBA 7.1 — last verified 2026-09-30.

Related guides: VBA Rename Sheet · VBA Hide Sheet · VBA Add Sheet · VBA Delete Sheet · VBA Worksheets · VBA On Error · VBA Like · VBA Open Workbook