SQLSTATE 25000Severity lowLab verified

Incident brief

COPY FREEZE with prior transaction activity

COPY ... WITH (FREEZE) was attempted while a cursor was still open in the same transaction. PostgreSQL refused because it can no longer guarantee no one else can see the pre-freeze rows.

Reproduced on PostgreSQL 16.14Verified 2026-07-16 (Docker lab, PostgreSQL 16.14)Reviewed by Verified against PostgreSQL 16.14 in an isolated lab environment

In 10 seconds

What
COPY FREEZE with prior transaction activity
What triggers it
Start a transaction, create a new table, and open a cursor (DECLARE ... CURSOR) that is still open.
The fix
Run COPY ... FREEZE before opening any cursor — the table just needs to have been created or truncated in the current transaction, with no cursors or older snapshots yet.
Proof
Reproduced on PostgreSQL 16.14 → COPY ... WITH (FREEZE) was rejected with SQLSTATE 25000 while a cursor was still open in the same transaction. The identical COPY FREEZE succeeded once it ran before the cursor was opened.

The fix

What to do right now

The immediate, application-level response to this error.

  • Run COPY ... FREEZE before opening any cursor — the table just needs to have been created or truncated in the current transaction, with no cursors or older snapshots yet.
  • Or move the cursor-based work into a separate transaction that runs after the COPY commits.
Fix — SQL
BEGIN;
CREATE TABLE batch8_freeze_demo (id int);
COPY batch8_freeze_demo FROM STDIN WITH (FREEZE);
1
2
\.
DECLARE freeze_demo_cur CURSOR FOR SELECT generate_series(1,3);
FETCH 1 FROM freeze_demo_cur;
COMMIT;

Related & next steps

Follow the thread

Everything this error touches — jump straight to the sibling error, term, runbook, or parameter.

Verification

PG 16.14
Last verified
2026-07-16 (Docker lab, PostgreSQL 16.14)
Reviewed by
Verified against PostgreSQL 16.14 in an isolated lab environment
Audit status
reviewed