Skip to content

25006 — read_only_sql_transaction

PostgreSQL SQLSTATE 25006: read-only transaction failures, diagnostics, and the transaction boundary needed for repair.

25006 — read_only_sql_transaction

At a glance

25006 is returned when a command would write in a read-only transaction. The selected case issues CREATE TABLE after SET TRANSACTION READ ONLY, observes INERROR, rolls back, and creates the table after leaving the read-only block.

Field Value
SQLSTATE 25006
Condition read_only_sql_transaction
Status active
Known present by 7.4
Locked snapshots 9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3
Macros ERRCODE_READ_ONLY_SQL_TRANSACTION
Aliases

Meaning

The code covers several guards. PreventCommandIfReadOnly formats the command name into cannot execute %s in a read-only transaction; the fixed source also has recovery-only messages for temporary tables and replication origins. The selected case covers the ordinary explicit read-only transaction path, while a standby or recovery path can use a different command-specific message.

Diagnosis

Record the exact command, SQLSTATE, severity, and transaction status. Before retrying, inspect the effective SHOW transaction_read_only and, for a server-level boundary, pg_is_in_recovery(); also identify whether a pool routed this connection to a standby. In the selected run, CREATE TABLE returns 25006 and leaves the explicit block INERROR; ROLLBACK is required before the same session can be used. A later CREATE TABLE outside the read-only block succeeds.

Response

Decide whether the operation belongs in a read-only transaction. If it must write, use a read/write transaction on the primary or run it outside the read-only block, and roll back the failed block before returning the connection to a pool. A standby or recovery-only 25006 path requires routing the operation to the primary; retrying the same write on the same target cannot change its access mode.

Source messages

The core utility template is cannot execute %s in a read-only transaction. The same utility guard uses cannot execute %s during recovery on a recovery target; recovery-only temporary-table and replication-origin paths have their own fixed text. %s is the executing command name, so these are not context-free static messages.

Observed diagnostics

18.6 (Homebrew) / latest: SQLSTATE 25006; primary cannot execute CREATE TABLE in a read-only transaction; INERROR → IDLE; repaired relation count 0; final IDLE. 10.21 (Debian 10.21-1.pgdg90+1) / pg10: SQLSTATE 25006; primary cannot execute CREATE TABLE in a read-only transaction; INERROR → IDLE; repaired relation count 0; final IDLE.

Representative case

The runner reads the setup, read-only transaction, rollback, and outside-block repair statements below from the shared registry; complete assertions, environment, and cleanup are in case export.

-- create
CREATE TABLE items(id integer PRIMARY KEY, note text NOT NULL);
-- begin
BEGIN;
-- read_only
SET TRANSACTION READ ONLY;
-- trigger
CREATE TABLE blocked(id integer PRIMARY KEY);
-- rollback
ROLLBACK;
-- repair
CREATE TABLE blocked(id integer PRIMARY KEY);
-- verify
SELECT count(*) FROM blocked;

The SQLSTATE, diagnostics, states, and repair assertions for this excerpt come from the shared registry (SHA-256 62db30e401b1f72fa50958d0ac612b2b1eb636299532dd1ad246c167e4f9fadf); structured evidence.

Authored evidence IDs: identity, utility-path, other-paths, runtime. Selected runtime records: runtime.25006-batch2-latest-20260909.latest, runtime.25006-batch2-pg10-20260909.pg10.

Versions and limits

The selected CREATE TABLE case passes on PostgreSQL 18.6 and 10.21 with the same primary text, INERROR → IDLE recovery, and a successful repaired relation. Other 25006 source paths remain outside this runtime case.

25P02 failed SQL transaction, 25001 active SQL transaction, 25P03 idle-in-transaction timeout.

Sources

  • src.errcodes.18.6 (SHA-256 6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba)
  • src.calls.REL_18_6raw/calls/REL_18_6.jsonl (SHA-256 9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf)
  • src.utility.18.6 (SHA-256 7aae5d07628b6debf8456d1d4ea96f28912232192e56ea25773b4c4b61235a00)
  • src.namespace.18.6 (SHA-256 8c9e6a99e84fa2cec8a9b1de2ecbe3966a13f4ad68c6ccfbfb8134a754d73e56)
  • src.origin.18.6 (SHA-256 81e5d5b4539b67bb372f0f0a05395af900c322cdbcec8a4b1f358333a16e6518)
  • doc.set-transaction.18.6 (SHA-256 33554463a2c9da1cf2c72cc27d4647d557204bb13a03cfeccb1b83f237a46589) · official documentation