Repository navigation
Using a completed NpgsqlTransaction silently causes command to execute without transaction #6149
Description
Activity
It is documented on the property itself.
npgsql/src/Npgsql/NpgsqlCommand.cs
Lines 1641 to 1650 in 1b55ebc
/// <summary> /// This property is ignored by Npgsql. PostgreSQL only supports a single transaction at a given time on /// a given connection, and all commands implicitly run inside the current transaction started via /// <see cref="NpgsqlConnection.BeginTransaction()"/> /// </summary> public new NpgsqlTransaction? Transaction { get => (NpgsqlTransaction?)DbTransaction; set => DbTransaction = value; } While we also can add that to our documentation, I'm not sure anyone will actually read it just for a basic property like that one.
It might be ignored by Npgsql, but the ExecuteNonQueryAsync and the rest of the Exexcute-methods, should raise an exception if the transaction being provided is ignored due to the Connection is null and IsComplete is true.
It seems dangerous to do something even though it's clearly not the desired behavior.
While I would rather not check that property every time we execute a query, we can probably assert each time that property is assigned. @roji do you think it makes sense?
It might be ignored by Npgsql, but the ExecuteNonQueryAsync and the rest of the Exexcute-methods, should raise an exception if the transaction being provided is ignored due to the Connection is null and IsComplete is true.
It seems dangerous to do something even though it's clearly not the desired behavior.Well, is it any different if someone assigns a non-finished NpgsqlTransaction (e.g. that belongs to a completely different connection) and it gets ignored as well? At the end of the day we simlpy ignore that property. Having said that...
While I would rather not check that property every time we execute a query, we can probably assert each time that property is assigned.
Yeah, that makes sense to me - a simple InvalidOperationException on assignment sounds reasonable...
Reacted by Nikita Kazmin- added a commit that references this issue
on Jul 2, 2025
When assigning an NpgsqlTransaction that has already been committed or rolled back to a NpgsqlCommand, the command executes without exception – but the transaction is silently ignored. This leads to the command being executed outside of any transaction, which is very dangerous and non-obvious.
Repro:
Expected behavior:
Throw an InvalidOperationException if the transaction has already been completed, or
At least log or document this behavior clearly.
Environment:
Npgsql version: 5.0.10
PostgreSQL version: 13.2
.NET version: .net core 6