25006
Read PG 18 manual ↗read_only_sql_transaction
- SQLSTATE
- 25006
- Condition name
- read_only_sql_transaction
- Class
- Invalid Transaction State
- Source macro
- ERRCODE_READ_ONLY_SQL_TRANSACTION
- Evidence
- Observed at runtime in the source evidence
English SQLSTATE atlas: authored explanations and source/runtime evidence are separate from the manual definitions. View source ↗
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.
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.
Sources
src.errcodes.18.6(SHA-2566e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba)src.calls.REL_18_6—raw/calls/REL_18_6.jsonl(SHA-2569ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf)src.utility.18.6(SHA-2567aae5d07628b6debf8456d1d4ea96f28912232192e56ea25773b4c4b61235a00)src.namespace.18.6(SHA-2568c9e6a99e84fa2cec8a9b1de2ecbe3966a13f4ad68c6ccfbfb8134a754d73e56)src.origin.18.6(SHA-25681e5d5b4539b67bb372f0f0a05395af900c322cdbcec8a4b1f358333a16e6518)doc.set-transaction.18.6(SHA-25633554463a2c9da1cf2c72cc27d4647d557204bb13a03cfeccb1b83f237a46589) · official documentation
Source evidence
Evidence belongs to the frozen source and runtime versions listed here. It is not a runtime verification of the selected manual version.
25006 is read_only_sql_transaction in Class 25.
Method: Read the fixed condition row and macro.
Limits: The same code covers more than one read-only/recovery guard.
PreventCommandIfReadOnly formats the SQL command name into “cannot execute %s in a read-only transaction”; CREATE TABLE is one ordinary utility path.
Method: Trace PreventCommandIfReadOnly and the documented read-only command restrictions.
Limits: The %s substitution is command-specific; recovery and parallel-operation paths have their own conditions/messages.
src.utility.18.6 src.calls.REL_18_6 doc.set-transaction.18.6
The fixed source also uses 25006 for temporary-table creation during recovery and replication-origin manipulation during recovery.
Method: Read the additional fixed source report groups.
Limits: Those recovery paths were not constructed by the selected ordinary read-only transaction case.
The selected read-only CREATE TABLE case returned 25006 on PostgreSQL 18.6 and 10.21, entered INERROR, recovered after ROLLBACK, and created the relation outside the read-only transaction.
Method: Read the selected summaries and structured diagnostics.
Limits: The case covers the ordinary explicit read-only utility path, not recovery-only temporary-table or replication-origin paths.
runtime runtime.25006-batch2-latest-20260909.latest runtime.25006-batch2-pg10-20260909.pg10
The same fixed utility source uses 25006 during recovery with the command-specific message "cannot execute %s during recovery"; this is separate from the selected ordinary read-only transaction path.
Method: Read the recovery guard and resolved report group in utility.c.
Limits: The %s substitution is command-specific; the selected runtime did not run on a standby or recovery target.
- src/backend/utils/errcodes.txt · REL_18_6 ·
724edf9bde9d356724ad384a2e196edc3c9f80f7 raw/calls/REL_18_6.jsonl· ·- src/backend/tcop/utility.c · REL_18_6 ·
724edf9bde9d356724ad384a2e196edc3c9f80f7 - src/backend/catalog/namespace.c · REL_18_6 ·
724edf9bde9d356724ad384a2e196edc3c9f80f7 - src/backend/replication/logical/origin.c · REL_18_6 ·
724edf9bde9d356724ad384a2e196edc3c9f80f7 - doc/src/sgml/ref/set_transaction.sgml · REL_18_6 ·
724edf9bde9d356724ad384a2e196edc3c9f80f7
Message templates
ERROR · utility
Primary
cannot execute %s in a read-only transaction
The %s substitution is the command name.
ERROR · utility-recovery
Primary
cannot execute %s during recovery
Recovery-only utility path; %s is the command name and this was not the selected ordinary read-only case.
ERROR · recovery-temp
Primary
cannot create temporary tables during recovery
A recovery-only path; not the selected case.
ERROR · recovery-origin
Primary
cannot manipulate replication origins during recovery
A recovery-only path; not the selected case.
Reproduction & repair cases
read_only_transaction · PG 10, 18
Preconditions
- A runner-owned disposable target is provisioned.
Trigger: Run CREATE TABLE after SET TRANSACTION READ ONLY.
Expected assertions
- SQLSTATE is 25006
- The CREATE TABLE read-only diagnostic is exact
- The failed transaction is INERROR, ROLLBACK restores IDLE
- The table can be created after leaving read-only mode
Repair: Follow the explicit transaction or source boundary described by the case.
Cleanup: Drop the case schema with an owner connection.
Recorded runtime evidence
18.6 (Homebrew) · passed
Run: 25006-batch2-latest-20260909
{
"primary": "cannot execute CREATE TABLE in a read-only transaction",
"sqlstate": "25006",
"after_error": "INERROR",
"final_status": "IDLE",
"after_rollback": "IDLE",
"repair_relation": "\"c25006_read_only_transaction\".\"blocked\"",
"rows_after_repair": 0
}10.21 (Debian 10.21-1.pgdg90+1) · passed
Run: 25006-batch2-pg10-20260909
{
"primary": "cannot execute CREATE TABLE in a read-only transaction",
"sqlstate": "25006",
"after_error": "INERROR",
"final_status": "IDLE",
"after_rollback": "IDLE",
"repair_relation": "\"c25006_read_only_transaction\".\"blocked\"",
"rows_after_repair": 0
}Definition snapshot: english-manuals:1caacfee5d940665bd4230e2b7f… · English manual source