Diagnostic Queries
Symptoms
A write was attempted in a read-only context — a read-only transaction, a hot-standby replica, or a server with default_transaction_read_only on. PostgreSQL raises SQLSTATE 25006 (read_only_sql_transaction).
- The message names the command (INSERT/UPDATE/DELETE/DDL).
- Very common when an app accidentally writes to a read replica.
- Also from
SET TRANSACTION READ ONLYor a read-only default.
What the server log shows
ERROR: cannot execute INSERT in a read-only transaction
Why PostgreSQL raises this — what the manual says
the SET TRANSACTION reference (Notes):
“When a transaction is read-only, the following SQL commands are disallowed:”
A read-only transaction (or a standby in recovery) forbids any statement that would change durable data. The write is rejected with 25006 before execution.
Common causes
- Routing writes to a read replica/standby.
default_transaction_read_only = onon the server.- An explicit
BEGIN … READ ONLYorSET TRANSACTION READ ONLY.
Relevant GUC parameters
| Parameter | Default | Effect |
|---|---|---|
default_transaction_read_only |
off | Makes new transactions read-only by default. |
transaction_read_only |
off | Read-only mode for the current transaction. |
How to fix it
- Send writes to the primary, not a replica (fix connection routing).
- Start a read/write transaction:
BEGIN; SET TRANSACTION READ WRITE;if appropriate. - Turn off
default_transaction_read_onlywhere writes are expected.
Related & next steps
Reference: PostgreSQL 18 — SET TRANSACTION.
Thanks — noted. This helps keep the database accurate.