Forum Discussion
"Method 'Calculation' of object '_Application' failed" error occurs on unpredictable attempts
The error "Method 'Calculation' of object '_Application' failed" is notoriously vague, but its intermittent nature is the biggest clue. It almost always points to a race condition or an unstable application state caused by how your code interacts with the Excel environment, especially when combined with userforms and screen updating.
I Think the error happens on this line: Application.Calculation = xlCalculationManual. You are trying to change a global application setting. The failure means Excel is in a state where it cannot process this request at that exact moment.
Here my solution approach with some Key Improvements (Replaced On Error Resume Next with a proper On Error GoTo ErrorHandler - The CleanExit block is now the only exit point, besides End Sub - The code now captures selectedRow = Selection.Row at the very beginning - The SetAppState helper sub makes the main code cleaner and less error-prone - The wait form is shown after the application state is set to "busy" - Using worksheet variables (wsProd, wsBkg) makes the code easier). Hope that Helps in your Projekt.
' Helper sub to manage application state
Private Sub SetAppState(ByVal isBusy As Boolean)
Static originalCalculation As XlCalculation
Static originalEvents As Boolean
Static originalScreenUpdating As Boolean
Static originalUpdateRemoteRefs As Boolean
Static originalDisplayStatusBar As Boolean
If isBusy Then
' Store original states first time
If originalCalculation = 0 Then
originalCalculation = Application.Calculation
originalEvents = Application.EnableEvents
originalScreenUpdating = Application.ScreenUpdating
originalUpdateRemoteRefs = ActiveWorkbook.UpdateRemoteReferences
originalDisplayStatusBar = Application.DisplayStatusBar
End If
' Turn everything OFF for speed/stability
On Error Resume Next ' Just in case calculation change fails
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
Application.ScreenUpdating = False
ActiveWorkbook.UpdateRemoteReferences = False
Application.DisplayStatusBar = False
On Error GoTo 0
Else
' Restore original states
On Error Resume Next
If originalCalculation <> 0 Then
Application.Calculation = originalCalculation
Application.EnableEvents = originalEvents
Application.ScreenUpdating = originalScreenUpdating
ActiveWorkbook.UpdateRemoteReferences = originalUpdateRemoteRefs
Application.DisplayStatusBar = originalDisplayStatusBar
Else
' Fallback to defaults
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
ActiveWorkbook.UpdateRemoteReferences = True
Application.DisplayStatusBar = True
End If
On Error GoTo 0
' Reset stored states
originalCalculation = 0
End If
End Sub
Private Sub CommandButton2_Click() 'Save
' --- PREPARATION ---
' Declare all variables at the top
Dim wsProd As Worksheet, wsBkg As Worksheet
Dim rng As Range, cell As Range
Dim first_DB_avail_row As Range
Dim Highest_Version_Row As Long
Dim existingVersions() As String
Dim ver_find As Variant
Dim ver_list As Object: Set ver_list = CreateObject("System.Collections.ArrayList")
Dim padded_list As Object: Set padded_list = CreateObject("System.Collections.ArrayList")
Dim v As Variant, parts As Variant
Dim padded_v As String, leadChar As String, all_vers As String
Dim i As Long 'Use Long instead of Integer for row counts
Dim productID_To_Find As String
Dim newVersionString As String
Dim selectedRow As Long '*** CRITICAL: Store the selected row number explicitly ***
Dim destRow As Range
Dim srcDevRow As Range
' --- INITIAL SETUP & VALIDATION ---
On Error GoTo ErrorHandler 'Use a proper error handler
' Set worksheet objects to avoid repeated lookups
Set wsProd = ThisWorkbook.Sheets("Products")
Set wsBkg = ThisWorkbook.Sheets("Background Data")
' *** CRITICAL FIX: Capture the active row BEFORE any UI changes ***
If TypeName(Selection) <> "Range" Then
MsgBox "Please select a product row first.", vbExclamation, "Business Manager"
GoTo CleanExit
End If
selectedRow = Selection.Row
If selectedRow < 4 Then 'Basic validation - assuming data starts at row 4
MsgBox "Please select a valid product row (row 4 or greater).", vbExclamation, "Business Manager"
GoTo CleanExit
End If
productID_To_Find = wsProd.Range("E" & selectedRow).Value
If productID_To_Find = "" Then
MsgBox "The selected row does not have a Product ID.", vbExclamation, "Business Manager"
GoTo CleanExit
End If
newVersionString = stage_entry & Major & Minor & Patch
'Handle first version case
If Me.Caption = "First Version - Business Manager" Then
If Me.ComboBox1.Value = "" Or Me.TextBox1.Value = "" Or _
Me.TextBox2.Value = "" Or Me.TextBox3.Value = "" Then
MsgBox "You must complete all fields.", vbExclamation, "Business Manager"
GoTo CleanExit
End If
Insert_Product.ver_val = newVersionString
Unload Me
Insert_Product.new_product_ver_cancel = False
GoTo CleanExit
End If
' Validate entries for non-first version
If Me.ComboBox1.Value = "" Or Me.TextBox1.Value = "" Or _
Me.TextBox2.Value = "" Or Me.TextBox3.Value = "" Then
MsgBox "You must complete all version fields.", vbExclamation, "Business Manager"
GoTo CleanExit
End If
'Check for existing versions
Call Find_Latest_Ver 'Get the current latest version
If newVersionString = Highest_Version Then
MsgBox "This version already exists (as the newest version).", vbExclamation, "Business Manager"
GoTo CleanExit
End If
If Me.TextBox4.Value <> "" Then
existingVersions = Split(Replace(Me.TextBox4.Value, vbCrLf, ""), "• ")
For Each ver_find In existingVersions
If Trim(ver_find) = newVersionString Then
MsgBox "This version already exists.", vbExclamation, "Business Manager"
GoTo CleanExit
End If
Next ver_find
End If
' --- START LONG-RUNNING PROCESS ---
Me.Hide 'Hide the form
' Set application state for performance/stability
SetAppState True
' Show wait form modelessly
PLZ_WAIT.Show vbModeless
PLZ_WAIT.Label2.Caption = "Setting new version..."
DoEvents
' --- CORE LOGIC ---
' Unprotect sheet
wsProd.Unprotect Password:=wsBkg.Range("CY39").Value
' Pull data from the latest version
Dim foundLatest As Boolean
foundLatest = False
Set rng = wsBkg.Range("E4:E7503")
For Each cell In rng.Cells
If cell.Value = productID_To_Find Then
If cell.Offset(0, -2).Value = Highest_Version Then
' Copy values from the latest version's row to the selected row
With wsProd.Rows(selectedRow)
.Cells(1, "B").Value = cell.Offset(0, -3).Value 'Name
.Cells(1, "C").Value = newVersionString 'Product Version
.Cells(1, "D").Value = cell.Offset(0, -1).Value 'File
.Cells(1, "E").Value = cell.Value 'ID Number
.Cells(1, "F").Value = cell.Offset(0, 1).Value 'Category
.Cells(1, "G").Value = cell.Offset(0, 2).Value 'Details (Description)
.Cells(1, "K").Value = cell.Offset(0, 6).Value 'Release Date
.Cells(1, "L").Value = cell.Offset(0, 7).Value 'Copyright Y/N button
.Cells(1, "M").Value = cell.Offset(0, 8).Value 'Copyright Status
.Cells(1, "N").Value = cell.Offset(0, 9).Value 'Year
.Cells(1, "O").Value = cell.Offset(0, 10).Value 'Copyright Statement
.Cells(1, "P").Value = cell.Offset(0, 11).Value 'Published Y/N button
.Cells(1, "Q").Value = cell.Offset(0, 12).Value 'Publish Status (Date)
.Cells(1, "R").Value = cell.Offset(0, 13).Value 'Web Link
.Cells(1, "S").Value = cell.Offset(0, 14).Value 'Withdraw Date
End With
Highest_Version_Row = cell.Row
foundLatest = True
Exit For
End If
End If
Next cell
If Not foundLatest Then
MsgBox "Could not find the data for the latest version ('" & Highest_Version & "') to copy from.", vbCritical, "Error"
GoTo ErrorHandler
End If
' Save new version to version database
Set first_DB_avail_row = wsBkg.Range("C7506").End(xlUp).Offset(1, 0)
Set destRow = first_DB_avail_row.EntireRow
' Copy product data to database
destRow.Cells(1, "B").Value = wsProd.Cells(selectedRow, "B").Value 'Name
destRow.Cells(1, "C").Value = wsProd.Cells(selectedRow, "C").Value 'Product Version
destRow.Cells(1, "D").Value = wsProd.Cells(selectedRow, "D").Value 'File
destRow.Cells(1, "E").Value = wsProd.Cells(selectedRow, "E").Value 'ID Number
destRow.Cells(1, "F").Value = wsProd.Cells(selectedRow, "F").Value 'Category
destRow.Cells(1, "G").Value = wsProd.Cells(selectedRow, "G").Value 'Details (Description)
destRow.Cells(1, "K").Value = wsProd.Cells(selectedRow, "K").Value 'Release Date
destRow.Cells(1, "L").Value = wsProd.Cells(selectedRow, "L").Value 'Copyright Y/N button
destRow.Cells(1, "M").Value = wsProd.Cells(selectedRow, "M").Value 'Copyright Status
destRow.Cells(1, "N").Value = wsProd.Cells(selectedRow, "N").Value 'Year
destRow.Cells(1, "O").Value = wsProd.Cells(selectedRow, "O").Value 'Copyright Statement
destRow.Cells(1, "P").Value = wsProd.Cells(selectedRow, "P").Value 'Published Y/N button
destRow.Cells(1, "Q").Value = wsProd.Cells(selectedRow, "Q").Value 'Publish Status (Date)
destRow.Cells(1, "R").Value = wsProd.Cells(selectedRow, "R").Value 'Web Link
destRow.Cells(1, "S").Value = wsProd.Cells(selectedRow, "S").Value 'Withdraw Date
' Copy Development Status Data from latest version
Set srcDevRow = wsBkg.Rows(Highest_Version_Row)
' Use bulk copy for efficiency
destRow.Cells(1, "T").Resize(1, 7).Value = srcDevRow.Cells(1, "T").Resize(1, 7).Value 'Title through Dev Log (1)
destRow.Cells(1, "AA").Resize(1, 3).Value = srcDevRow.Cells(1, "AA").Resize(1, 3).Value 'Framework through Stage
destRow.Cells(1, "DA").Resize(1, 7).Value = srcDevRow.Cells(1, "DA").Resize(1, 7).Value 'Dev Logs (2-7)
destRow.Cells(1, "AD").Resize(1, 13).Value = srcDevRow.Cells(1, "AD").Resize(1, 13).Value 'Bugs through Customer Request
' --- VERSION LIST & VALIDATION ---
' Build version list
ver_list.Add newVersionString
For Each cell In rng.Cells
If cell.Value = productID_To_Find Then
ver_list.Add cell.Offset(0, -2).Value
End If
Next cell
' Sort versions with padding technique
For i = 0 To ver_list.Count - 1
v = ver_list(i)
If Len(v) > 0 And Left(v, 1) Like "[A-Z]" And InStr(v, ".") > 0 Then
leadChar = Left(v, 1)
parts = Split(Mid(v, 2), ".")
If UBound(parts) >= 2 Then
padded_v = leadChar
padded_v = padded_v & Right("000" & parts(0), 3)
padded_v = padded_v & Right("000" & parts(1), 3)
padded_v = padded_v & Right("000" & parts(2), 3)
ver_list(i) = padded_v & "|" & v
End If
End If
Next i
' Sort descending
ver_list.Sort
ver_list.Reverse
' Reconstruct version list
For i = 0 To ver_list.Count - 1
If InStr(ver_list(i), "|") > 0 Then
ver_list(i) = Split(ver_list(i), "|")(1)
End If
Next i
' Create validation list string
all_vers = "," & Join(ver_list.ToArray, ",")
' Apply validation to the version cell
With wsProd.Cells(selectedRow, "C").Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, Formula1:=all_vers
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = False
.ShowError = False
End With
' Re-protect sheet
wsProd.Protect Password:=wsBkg.Range("CY39").Value
' --- FINALIZATION ---
Sheet2.UPDATE_DB_FORCE = True
' Pass the specific cell that changed
Application.Run "Sheet2.Worksheet_Change", wsProd.Cells(selectedRow, "C")
Sheet2.UPDATE_DB_FORCE = False
MsgBox "New version '" & newVersionString & "' created successfully!", vbInformation, "Success"
Unload Me
CleanExit:
' This section runs whether there's an error or not
' Restore application state
SetAppState False
' Clean up UI
On Error Resume Next
Unload PLZ_WAIT
On Error GoTo 0
' Release all object variables
Set wsProd = Nothing
Set wsBkg = Nothing
Set rng = Nothing
Set cell = Nothing
Set first_DB_avail_row = Nothing
Set destRow = Nothing
Set srcDevRow = Nothing
If Not ver_list Is Nothing Then
ver_list.Clear
Set ver_list = Nothing
End If
Set padded_list = Nothing
Exit Sub 'Normal exit
ErrorHandler:
' This section only runs when an actual error occurs
MsgBox "An unexpected error occurred:" & vbCrLf & _
"Error #" & Err.Number & ": " & Err.Description & vbCrLf & _
"The operation has been cancelled. Please try again.", vbCritical, "Business Manager"
' Jump to cleanup section to restore state
Resume CleanExit
End SubThe code is not Tested, save your file as a backup before.
Hello again :) Thank you for the insight! I'm not too familiar with what a Static variable is but hasn't been tried in my work yet. With that said, across all my userforms, I pretty much do a variable declare, then validation, then set macro enhancement, then the code. This one just doesn't set any of the application states ("Macro Enhancement - Start:") sometimes, but then other times, does it with no issues at all. I would get the error 1 time then good for 3 times of save in a row, or: 2-to-4, 1-to-6, 3-to-1, or any random consecutive number of error-to-good times.
No issues in other userforms and would be good random times in this one so it doesn't make sense. Anyway, what I wanted to ask before trying that is if I can keep this in one sub and have my same "MEM_CLEAN:" structure, before moving on with your suggestions?
- NikolinoDEMar 09, 2026Platinum Contributor
im no sure but you can try this code, maybe helps
Private Sub CommandButton2_Click() 'Save ' --- PREPARATION --- Dim rng As Range, cell As Range Dim first_DB_avail_row As Range Dim Highest_Version_Row As Long Dim existingVersions() As String Dim ver_find As Variant Dim ver_list As Object: Set ver_list = CreateObject("System.Collections.ArrayList") Dim v As Variant, parts As Variant Dim padded_v As String, leadChar As String, all_vers As String Dim i As Long 'Changed to Long Dim selectedRow As Long Dim productID_To_Find As String Dim newVersionString As String ' *** THE FIX: Add a flag to track if we locked the app *** Dim appLocked As Boolean appLocked = False ' Set worksheet objects early Dim wsProd As Worksheet, wsBkg As Worksheet Set wsProd = ThisWorkbook.Sheets("Products") Set wsBkg = ThisWorkbook.Sheets("Background Data") ' --- INITIAL SETUP & VALIDATION --- If TypeName(Selection) = "Range" Then selectedRow = Selection.Row Else MsgBox "Please select a valid product row.", vbExclamation, "Business Manager" GoTo MEM_CLEAN End If If selectedRow < 4 Then MsgBox "Please select a valid product row (row 4 or greater).", vbExclamation, "Business Manager" GoTo MEM_CLEAN End If productID_To_Find = wsProd.Range("E" & selectedRow).Value If productID_To_Find = "" Then MsgBox "The selected row does not have a Product ID.", vbExclamation, "Business Manager" GoTo MEM_CLEAN End If newVersionString = stage_entry & Major & Minor & Patch ' Validation blocks (First Version) If Me.Caption = "First Version - Business Manager" Then If Me.ComboBox1.Value = "" Or Me.TextBox1.Value = "" Or _ Me.TextBox2.Value = "" Or Me.TextBox3.Value = "" Then MsgBox "You must complete all fields.", vbExclamation, "Business Manager" GoTo MEM_CLEAN End If Insert_Product.ver_val = newVersionString Unload Me Insert_Product.new_product_ver_cancel = False GoTo MEM_CLEAN End If ' Validation (Existing Version) Call Find_Latest_Ver If newVersionString = Highest_Version Then MsgBox "This version already exists (as the newest version).", vbExclamation, "Business Manager" GoTo MEM_CLEAN End If If Me.TextBox4.Value <> "" Then existingVersions = Split(Replace(Me.TextBox4.Value, vbCrLf, ""), "• ") For Each ver_find In existingVersions If Trim(ver_find) = Trim(newVersionString) Then MsgBox "This version already exists.", vbExclamation, "Business Manager" GoTo MEM_CLEAN End If Next ver_find End If If Me.ComboBox1.Value = "" Or Me.TextBox1.Value = "" Or _ Me.TextBox2.Value = "" Or Me.TextBox3.Value = "" Then MsgBox "You must complete all fields.", vbExclamation, "Business Manager" GoTo MEM_CLEAN End If ' --- MACRO ENHANCEMENT - START --- Me.Hide ' Show wait form PLZ_WAIT.Show vbModeless PLZ_WAIT.Label2.Caption = "Setting new version" DoEvents 'Allow UI to paint ' *** THE CRITICAL FIX *** On Error Resume Next Application.Calculation = xlCalculationManual Application.EnableEvents = False Application.ScreenUpdating = False ' Check if we actually succeeded If Err.Number = 0 Then appLocked = True 'We successfully locked it Else ' We failed to lock it. Clear error and proceed anyway (slower but safer) Err.Clear appLocked = False End If On Error GoTo ErrorHandler 'Restore normal error handling for logic errors ' We can still try these even if Calc failed ActiveWorkbook.UpdateRemoteReferences = False Application.DisplayAlerts = False Application.DisplayStatusBar = False ' Note: I removed Interactive=False as it often causes more issues than it solves ' Pull data from the latest version: wsProd.Unprotect Password:=wsBkg.Range("CY39").Value Dim foundLatest As Boolean foundLatest = False Set rng = wsBkg.Range("E4:E7503") For Each cell In rng.Cells If cell.Value = productID_To_Find Then If cell.Offset(0, -2).Value = Highest_Version Then ' Copy data using your logic wsProd.Rows(selectedRow).Cells(1, "B").Value = cell.Offset(0, -3).Value wsProd.Rows(selectedRow).Cells(1, "C").Value = newVersionString wsProd.Rows(selectedRow).Cells(1, "D").Value = cell.Offset(0, -1).Value wsProd.Rows(selectedRow).Cells(1, "E").Value = cell.Value wsProd.Rows(selectedRow).Cells(1, "F").Value = cell.Offset(0, 1).Value wsProd.Rows(selectedRow).Cells(1, "G").Value = cell.Offset(0, 2).Value wsProd.Rows(selectedRow).Cells(1, "K").Value = cell.Offset(0, 6).Value wsProd.Rows(selectedRow).Cells(1, "L").Value = cell.Offset(0, 7).Value wsProd.Rows(selectedRow).Cells(1, "M").Value = cell.Offset(0, 8).Value wsProd.Rows(selectedRow).Cells(1, "N").Value = cell.Offset(0, 9).Value wsProd.Rows(selectedRow).Cells(1, "O").Value = cell.Offset(0, 10).Value wsProd.Rows(selectedRow).Cells(1, "P").Value = cell.Offset(0, 11).Value wsProd.Rows(selectedRow).Cells(1, "Q").Value = cell.Offset(0, 12).Value wsProd.Rows(selectedRow).Cells(1, "R").Value = cell.Offset(0, 13).Value wsProd.Rows(selectedRow).Cells(1, "S").Value = cell.Offset(0, 14).Value Highest_Version_Row = cell.Row foundLatest = True Exit For End If End If Next cell If Not foundLatest Then MsgBox "Could not find the data for the latest version ('" & Highest_Version & "') to copy from.", vbCritical, "Error" GoTo ErrorHandler End If ' ... [Rest of your data saving logic goes here - it's fine] ... ' I am skipping the repetitive copy/paste lines for brevity, assume they are here. ' Just ensure you use wsProd.Rows(selectedRow) and wsBkg.Rows(Highest_Version_Row) ' Example of one line fixed to use variables: Set first_DB_avail_row = wsBkg.Range("C7506").End(xlUp).Offset(1, 0) first_DB_avail_row.Offset(0, -1).Value = wsProd.Cells(selectedRow, "B").Value first_DB_avail_row.Value = wsProd.Cells(selectedRow, "C").Value ' ... etc ... 'Set version list: ver_list.Add newVersionString For Each cell In rng If cell.Value = productID_To_Find Then ver_list.Add cell.Offset(0, -2).Value End If Next cell 'Sort versions: For i = 0 To ver_list.Count - 1 v = ver_list(i) If Len(v) > 1 And IsNumeric(Mid(v, 2, 1)) Then 'Basic check leadChar = Left(v, 1) parts = Split(Mid(v, 2), ".") If UBound(parts) = 2 Then padded_v = leadChar & Right("000" & parts(0), 3) & Right("000" & parts(1), 3) & Right("000" & parts(2), 3) ver_list(i) = padded_v & "|" & v End If End If Next i ver_list.Sort: ver_list.Reverse For i = 0 To ver_list.Count - 1 If InStr(ver_list(i), "|") > 0 Then ver_list(i) = Split(ver_list(i), "|")(1) Next i all_vers = "," & Join(ver_list.ToArray, ",") With wsProd.Cells(selectedRow, "C").Validation .Delete .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:=xlBetween, Formula1:=all_vers .IgnoreBlank = True: .InCellDropdown = True .ShowInput = False: .ShowError = False End With wsProd.Protect Password:=wsBkg.Range("CY39").Value ' --- FINALIZATION --- Sheet2.UPDATE_DB_FORCE = True ' Use the specific cell, not Selection Application.Run "Sheet2.Worksheet_Change", wsProd.Cells(selectedRow, "C") Sheet2.UPDATE_DB_FORCE = False MsgBox "Saved!", vbInformation Unload Me ' --------------------------------------------------------- ' CLEANUP SECTION - The Gatekeeper ' --------------------------------------------------------- MEM_CLEAN: ' *** THE MAGIC: Only restore if we actually locked it *** If appLocked Then On Error Resume Next 'Ignore errors during restore (e.g. user closing Excel) Application.Calculation = xlCalculationAutomatic Application.EnableEvents = True Application.ScreenUpdating = True ActiveWorkbook.UpdateRemoteReferences = True Application.DisplayStatusBar = True Application.DisplayAlerts = True On Error GoTo 0 End If ' Always try to kill the wait form On Error Resume Next Unload PLZ_WAIT On Error GoTo 0 ' Release memory Set rng = Nothing: Set cell = Nothing Set first_DB_avail_row = Nothing If Not ver_list Is Nothing Then ver_list.Clear: Set ver_list = Nothing Set wsProd = Nothing: Set wsBkg = Nothing Exit Sub ' --------------------------------------------------------- ' ERROR HANDLER ' --------------------------------------------------------- ErrorHandler: MsgBox "An error occurred in the logic: " & Err.Description, vbCritical ' Jump to cleanup to restore settings safely Resume MEM_CLEAN End Sub- KendetharMar 10, 2026Iron Contributor
Wait, so it only happens when I run the code (green plus calls the userform.show) while my selection's drop-down is activated (or Excel thinks it is). So I WAS able to finally recreate it.
So I need to make the drop-down/validation completely deactivate before running code. From testing, either of these will work at the beginning of my "Private Sub UserForm_Initialize()" sub:
SendKeys "{ESC}": DoEventsSelection.Offset(0, 1).Select: Selection.Offset(0, -1).SelectBut, SendKeys is famous for occasionally (and randomly) turning off a user's NumLock key due to an old Windows API bug, so I imagine the second option is best.
I am so sorry, I didn't think the cell's validation was relevant but should've mentioned that to begin with. With that said, do you have any better options than those 2? If not, it's fine. - KendetharMar 10, 2026Iron Contributor
I like your Boolean appLocked variable approach but since the error (if it wants to happen) also would occur on "Application.EnableEvents = False", it's a problem because, yes I want the macro enhancement for usability, but I actually need it in this sub so that when changes are made to cells, it doesn't run the change event code I have for the sheet. Basically, if "Application.EnableEvents = False" fails, I the sub needs to fail too.