- Error number
- 6401
- Severity
- 16 (user-correctable error)
- State
- 1
- Product
- Microsoft SQL Server Database Engine
- Versions
- All supported SQL Server versions (2016 to 2025), Azure SQL Database, Azure SQL Managed Instance
- Category
- Transactions
- Last reviewed
- 24 October 2026
On this page
What it means
Error 6401 means ROLLBACK TRANSACTION named a savepoint or transaction that does not exist in the open transaction, so nothing was rolled back and the transaction is still open.
ROLLBACK TRANSACTION name accepts only two kinds of name: a savepoint created with SAVE TRANSACTION in the current transaction, or the name given to the outermost BEGIN TRANSACTION. Anything else, the word after "Cannot roll back" in the message, is rejected with 6401 at severity 16. Read that word first: it is the name SQL Server looked for, so a typo or a variable holding the wrong value is visible straight away.
The important part is what did not happen. In our tests the statement undid nothing, @@TRANCOUNT stayed the same and XACT_STATE() stayed 1, so the transaction is still open and holding its locks. If the code carries on as if the rollback worked, the changes it meant to discard can still be committed later. This is different from error 3903, which you get when there is no transaction at all (even with a name), and from error 3902 on the COMMIT side.
Common causes
- A typo or a different spelling in the savepoint name, or a variable that holds another value than the one used in SAVE TRANSACTION.
- Rolling back to the name of an inner
BEGIN TRANSACTION. SQL Server has no real nested transactions; only the outermost transaction name and savepoints are valid targets. - Rolling back to the same savepoint a second time, for example in a retry loop. On SQL Server 2025 we observed that rolling back to a savepoint uses it up, so the second ROLLBACK fails unless the loop saves it again.
- A savepoint from an earlier transaction: after COMMIT or a full ROLLBACK, savepoints are gone and the next transaction does not know them.
- A procedure that rolls back to a savepoint its caller created under another name, or that assumes the caller created one.
Diagnose it
Read-only These queries only read metadata and dynamic management views. They do not change data, permissions or configuration, so they are safe to run first.
Is a transaction still open after the failed ROLLBACK?
SELECT @@TRANCOUNT AS trancount,
XACT_STATE() AS xact_state; -- 1 active, -1 doomed, 0 none After 6401 you will normally see a count of 1 or more and state 1: the transaction is alive and must still be committed or rolled back. Run this in the same session, right after the error.
What is the outermost transaction called?
Only this name (or a savepoint) can be used with ROLLBACK TRANSACTION. Unnamed transactions are listed as user_transaction.
SELECT at.transaction_id, at.name, at.transaction_begin_time
FROM sys.dm_tran_session_transactions AS st
JOIN sys.dm_tran_active_transactions AS at
ON at.transaction_id = st.transaction_id
WHERE st.session_id = @@SPID; One row for an open transaction, with the name given to the outermost BEGIN TRANSACTION. Names given to inner BEGIN TRANSACTION statements never appear here.
Find modules that use named rollbacks or savepoints
A text search to list the code worth reviewing. Compare the names used in SAVE TRANSACTION and ROLLBACK TRANSACTION in each hit.
SELECT OBJECT_SCHEMA_NAME(m.object_id) AS schema_name, OBJECT_NAME(m.object_id) AS module_name
FROM sys.sql_modules AS m
WHERE m.definition LIKE N'%SAVE TRAN%'
OR m.definition LIKE N'%BEGIN TRANSACTION [A-Za-z@]%'
OR m.definition LIKE N'%BEGIN TRAN [A-Za-z@]%'; Procedures and triggers that create savepoints or named transactions. A name in ROLLBACK that has no matching SAVE TRANSACTION (or outermost BEGIN TRANSACTION name) in the same transaction path is a candidate for 6401.
How to fix it
Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.
Use the exact savepoint name, kept in one place
Changes dataStore the savepoint name in a variable and use that variable for both SAVE and ROLLBACK, so the two cannot drift apart. Both statements accept a variable.
DECLARE @sp sysname = N'BeforeUpdate';
BEGIN TRANSACTION;
SAVE TRANSACTION @sp;
UPDATE dbo.Orders SET status = 'paid' WHERE id = 1;
IF @@ROWCOUNT <> 1
ROLLBACK TRANSACTION @sp; -- undo only the work since the savepoint
COMMIT TRANSACTION;
Roll back the whole transaction without an inner name
Changes dataTo undo everything, use plain ROLLBACK TRANSACTION (or the outermost name). To undo only the inner part, replace the inner BEGIN TRANSACTION with a SAVE TRANSACTION, because an inner BEGIN only increments @@TRANCOUNT.
BEGIN TRANSACTION;
SAVE TRANSACTION InnerWork; -- instead of BEGIN TRANSACTION InnerTran
INSERT INTO dbo.Orders VALUES (1, 'new');
ROLLBACK TRANSACTION InnerWork; -- undoes the insert only
COMMIT TRANSACTION;
Save the savepoint again on every retry
Changes dataIn a retry loop, put SAVE TRANSACTION inside the loop so every attempt has its own savepoint to roll back to.
DECLARE @try int = 1;
BEGIN TRANSACTION;
WHILE @try <= 3
BEGIN
SAVE TRANSACTION Attempt; -- a fresh savepoint for this attempt
BEGIN TRY
INSERT INTO dbo.Orders VALUES (10 + @try, 'new');
BREAK;
END TRY
BEGIN CATCH
IF XACT_STATE() = -1 THROW; -- doomed: only a full rollback is possible
ROLLBACK TRANSACTION Attempt;
SET @try += 1;
END CATCH;
END;
COMMIT TRANSACTION;
Treat 6401 as a failure, not as a completed rollback
Changes dataThe transaction is still open after 6401. In a CATCH block, end it explicitly and rethrow, so nothing that should have been undone is committed by a later statement.
BEGIN CATCH
IF XACT_STATE() <> 0
ROLLBACK TRANSACTION; -- full rollback, no name
THROW;
END CATCH;
Examples
A typo in the savepoint name
SET NOCOUNT ON;
CREATE TABLE dbo.Orders (id INT PRIMARY KEY, status VARCHAR(10));
GO
BEGIN TRANSACTION;
SAVE TRANSACTION BeforeUpdate;
UPDATE dbo.Orders SET status = 'paid' WHERE id = 1;
ROLLBACK TRANSACTION BeforeUpdte; -- typo: no savepoint of that name
SELECT @@TRANCOUNT AS trancount; -- still 1: nothing was rolled back
ROLLBACK TRANSACTION;
Msg 6401, Level 16, State 1, Line 4 Cannot roll back BeforeUpdte. No transaction or savepoint of that name was found.
Reproduced on SQL Server 2025 (17.0.1145.4), 23 October 2026.
Rolling back an inner named transaction
The inner name is accepted by BEGIN TRANSACTION but cannot be rolled back to. After the error @@TRANCOUNT is still 2.
SET NOCOUNT ON;
CREATE TABLE dbo.Orders (id INT PRIMARY KEY, status VARCHAR(10));
GO
BEGIN TRANSACTION OuterTran;
BEGIN TRANSACTION InnerTran;
INSERT INTO dbo.Orders VALUES (1, 'new');
ROLLBACK TRANSACTION InnerTran; -- only OuterTran or a savepoint is valid here
SELECT @@TRANCOUNT AS trancount; -- 2
ROLLBACK TRANSACTION;
Msg 6401, Level 16, State 1, Line 4 Cannot roll back InnerTran. No transaction or savepoint of that name was found.
Reproduced on SQL Server 2025 (17.0.1145.4), 23 October 2026.
A retry rolls back to the same savepoint twice
The first ROLLBACK to the savepoint works; the second fails because the savepoint was not saved again. Observed on SQL Server 2025.
SET NOCOUNT ON;
CREATE TABLE dbo.Orders (id INT PRIMARY KEY, status VARCHAR(10));
GO
BEGIN TRANSACTION;
SAVE TRANSACTION Attempt;
INSERT INTO dbo.Orders VALUES (1, 'new');
ROLLBACK TRANSACTION Attempt; -- first retry: works
INSERT INTO dbo.Orders VALUES (1, 'new');
ROLLBACK TRANSACTION Attempt; -- second retry: the savepoint is used up
ROLLBACK TRANSACTION;
Msg 6401, Level 16, State 1, Line 6 Cannot roll back Attempt. No transaction or savepoint of that name was found.
Reproduced on SQL Server 2025 (17.0.1145.4), 23 October 2026.
How to prevent it
Name only what you roll back to: use SAVE TRANSACTION for partial rollbacks and leave inner BEGIN TRANSACTION statements unnamed (or avoid them). Keep a savepoint name in one variable, create the savepoint inside any loop that rolls back to it, and never roll back to a savepoint you did not create in the same procedure.
Make every CATCH block end with a known transaction state: roll back fully when XACT_STATE() <> 0 and rethrow. For how savepoints, nesting and @@TRANCOUNT interact, see managing transactions and concurrency.
Common questions
Is my transaction rolled back after error 6401?
No. Nothing was undone and the transaction is still open with its locks. Commit or roll it back explicitly, or the connection keeps it open until it closes.
Why can I BEGIN TRANSACTION InnerTran but not roll it back?
Inner BEGIN TRANSACTION statements only increase @@TRANCOUNT; their names are not recorded as rollback targets. Use SAVE TRANSACTION for a point you want to return to.
Can I roll back to the same savepoint more than once?
In our tests on SQL Server 2025, no: the second ROLLBACK to the same name raised 6401. Save the savepoint again before each piece of work you may want to undo.
Learn more on CodeWithSQL
- Managing transactions and concurrency
- Transactions and concurrency
- SQL transactions and ACID explained
Official documentation
- ROLLBACK TRANSACTION (Transact-SQL)
- SAVE TRANSACTION (Transact-SQL)
- BEGIN TRANSACTION (Transact-SQL)
- Database Engine events and errors 6000 to 6999
Last technically reviewed 24 October 2026; examples and diagnostics run on SQL Server 2025 (17.0.1145.4). Message text checked against the engine's sys.messages catalogue.