Skip to content

Commit a07ea81

Browse files
fix: raise InterfaceError for nested transactions instead of OperationalError(0)
Nested transactions are client-side misuse, not a server operational error. Using OperationalError with code=0 (SQLITE_OK) was semantically incorrect. InterfaceError is the right exception type, consistent with how _check_in_use() handles other misuse patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 84cbd42 commit a07ea81

2 files changed

Lines changed: 10 additions & 13 deletions

File tree

src/dqliteclient/connection.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,7 @@ async def fetchval(self, sql: str, params: Sequence[Any] | None = None) -> Any:
305305
async def transaction(self) -> AsyncIterator[None]:
306306
"""Context manager for transactions."""
307307
if self._in_transaction:
308-
raise OperationalError(
309-
0, "Nested transactions are not supported; use SAVEPOINT directly"
310-
)
308+
raise InterfaceError("Nested transactions are not supported; use SAVEPOINT directly")
311309

312310
self._in_transaction = True
313311
self._tx_owner = asyncio.current_task()

tests/test_connection.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,10 @@ async def mock_execute(sql: str, params=None):
210210

211211
conn.execute = mock_execute # type: ignore[assignment]
212212

213-
from dqliteclient.exceptions import OperationalError
213+
from dqliteclient.exceptions import InterfaceError
214214

215215
async with conn.transaction():
216-
with pytest.raises(OperationalError, match="[Nn]ested"):
216+
with pytest.raises(InterfaceError, match="[Nn]ested"):
217217
async with conn.transaction():
218218
pass
219219

@@ -816,11 +816,11 @@ async def do_execute():
816816
with pytest.raises(asyncio.CancelledError):
817817
await task
818818

819-
async def test_concurrent_transaction_raises_operational_error(self) -> None:
820-
"""Second concurrent transaction() must raise OperationalError, not InterfaceError."""
819+
async def test_concurrent_transaction_raises_interface_error(self) -> None:
820+
"""Second concurrent transaction() must raise InterfaceError about nesting."""
821821
import asyncio
822822

823-
from dqliteclient.exceptions import InterfaceError, OperationalError
823+
from dqliteclient.exceptions import InterfaceError
824824

825825
conn = DqliteConnection("localhost:9001")
826826

@@ -863,22 +863,21 @@ async def tx_b():
863863
try:
864864
async with conn.transaction():
865865
pass
866-
except (OperationalError, InterfaceError) as e:
866+
except InterfaceError as e:
867867
errors.append(e)
868868

869869
task_a = asyncio.create_task(tx_a())
870870
task_b = asyncio.create_task(tx_b())
871871

872-
await task_b # should raise OperationalError about nested transactions
872+
await task_b # should raise InterfaceError about nested transactions
873873

874874
task_a.cancel()
875875
with pytest.raises(asyncio.CancelledError):
876876
await task_a
877877

878878
assert len(errors) == 1
879-
# Must get OperationalError about nested transactions, NOT InterfaceError
880-
assert isinstance(errors[0], OperationalError), (
881-
f"Expected OperationalError about nested transactions, "
879+
assert isinstance(errors[0], InterfaceError), (
880+
f"Expected InterfaceError about nested transactions, "
882881
f"got {type(errors[0]).__name__}: {errors[0]}"
883882
)
884883
assert "Nested" in str(errors[0]) or "nested" in str(errors[0])

0 commit comments

Comments
 (0)