From eb95c0f9f15c43e9a8776ec2460c581f784852e7 Mon Sep 17 00:00:00 2001 From: Erik Darling <2136037+erikdarlingdata@users.noreply.github.com> Date: Sun, 29 Mar 2026 14:17:20 -0400 Subject: [PATCH] Fix doomed transaction error handling in delta framework and ensure_collection_table (#756) When calculate_deltas was called inside a collector's transaction and failed, the CATCH block tried to INSERT into collection_log while the transaction was doomed (XACT_STATE = -1), swallowing the real error with "The current transaction cannot be committed." Same pattern in ensure_collection_table where INSERT happened before ROLLBACK. Co-Authored-By: Claude Opus 4.6 (1M context) --- install/05_delta_framework.sql | 47 ++++++++++++++------------ install/06_ensure_collection_table.sql | 11 +++--- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/install/05_delta_framework.sql b/install/05_delta_framework.sql index b0e87b28..688e87c3 100644 --- a/install/05_delta_framework.sql +++ b/install/05_delta_framework.sql @@ -1202,38 +1202,43 @@ BEGIN END TRY BEGIN CATCH + DECLARE + @error_message nvarchar(4000) = ERROR_MESSAGE(); + /* Only rollback if we started the transaction Otherwise let the caller handle it */ - IF @trancount_at_entry = 0 + IF @trancount_at_entry = 0 AND @@TRANCOUNT > 0 BEGIN ROLLBACK TRANSACTION; END; - DECLARE - @error_message nvarchar(4000) = ERROR_MESSAGE(); - /* - Log the error + Log the error only if the transaction is not doomed + When called inside a caller's transaction that is doomed (XACT_STATE = -1), + we cannot write to the log — the caller must rollback first */ - INSERT INTO - config.collection_log - ( - collector_name, - collection_status, - duration_ms, - error_message - ) - VALUES - ( - N'calculate_deltas_' + @table_name, - N'ERROR', - DATEDIFF(MILLISECOND, @start_time, SYSDATETIME()), - @error_message - ); - + IF XACT_STATE() <> -1 + BEGIN + INSERT INTO + config.collection_log + ( + collector_name, + collection_status, + duration_ms, + error_message + ) + VALUES + ( + N'calculate_deltas_' + @table_name, + N'ERROR', + DATEDIFF(MILLISECOND, @start_time, SYSDATETIME()), + @error_message + ); + END; + RAISERROR(N'Error calculating deltas for %s: %s', 16, 1, @table_name, @error_message); END CATCH; END; diff --git a/install/06_ensure_collection_table.sql b/install/06_ensure_collection_table.sql index c47e67eb..414d5b1d 100644 --- a/install/06_ensure_collection_table.sql +++ b/install/06_ensure_collection_table.sql @@ -1206,8 +1206,14 @@ BEGIN BEGIN CATCH SET @error_message = ERROR_MESSAGE(); + IF @@TRANCOUNT > 0 + BEGIN + ROLLBACK; + END; + /* Log errors to collection log + Must happen after rollback to avoid doomed transaction writes */ INSERT INTO config.collection_log @@ -1229,11 +1235,6 @@ BEGIN @error_message ); - IF @@TRANCOUNT > 0 - BEGIN - ROLLBACK; - END; - THROW; END CATCH; END;