Skip to main content

PG.L6.DEFAULT_TRANSACTION_ISOLATION_DRIFT — a new error class your code has no reason to handle

  • Category: safety
  • Level: 6
  • Confidence: heuristic
  • Downtime class: none
  • Stability: stable
  • Suites: audit
  • Applies to: PostgreSQL 18

read committed is PostgreSQL's default, and it is what Laravel's transaction handling is written against. Raising the server-wide default to repeatable read or serializable changes what every transaction does — including the ones the framework opens on your behalf, which no application code ever looks at.

At a higher level a transaction can fail with a serialization failure (SQLSTATE 40001) instead of blocking. That error is designed to be retried. Code written against the defaults has no reason to retry it, because at read committed it never happens.

So the failure appears under concurrency, in production, in a code path nobody wrote error handling for — and not once in development.

Why the finding is worded as a consequence, not a mistake

An application that deliberately runs serializable and has written the retry handling to match is the expected exception, not a defect. Raising isolation is a legitimate, sometimes necessary choice; what makes it a finding is that the choice was made server-wide, where the code that has to cope with it cannot see it.

That case belongs on the ignore list, with the reason recorded there:

'ignore' => [
['rule' => 'PG.L6.DEFAULT_TRANSACTION_ISOLATION_DRIFT', 'reason' => 'the ledger service runs serializable and retries 40001'],
],

Server value, not session value

The check reads the server's default — what a connection gets when nothing else has spoken. A connection that raised its own level is doing something local and deliberate, and produces no server finding.

Flagged

ALTER SYSTEM SET default_transaction_isolation = 'serializable';
SELECT pg_reload_conf();

Preferred

ALTER SYSTEM SET default_transaction_isolation = 'read committed';
SELECT pg_reload_conf();

Then raise it where you need it — SET TRANSACTION ISOLATION LEVEL SERIALIZABLE at the start of the transaction that actually requires it, next to the retry loop that handles the consequence.

Sources