SQLSTATE 34000Severity lowLab verified

Incident brief

Cursor does not exist

A CLOSE (or FETCH/MOVE) named a cursor that was never declared, or was already closed. PostgreSQL has no OPEN statement — a cursor exists only once you DECLARE it.

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

In 10 seconds

What
Cursor does not exist
What triggers it
Begin a transaction.
The fix
DECLARE the cursor before you FETCH, MOVE, or CLOSE it — there is no implicit OPEN.
Proof
Reproduced on PostgreSQL 16.14 → CLOSE of an undeclared cursor was rejected with SQLSTATE 34000, aborting the transaction. Declaring the cursor first let FETCH and CLOSE succeed.

The fix

What to do right now

The immediate, application-level response to this error.

  • DECLARE the cursor before you FETCH, MOVE, or CLOSE it — there is no implicit OPEN.
  • Remember non-holdable cursors are implicitly closed at COMMIT/ROLLBACK; don't reuse the name across transactions.
  • Query pg_cursors to see which cursors are actually open in the current session.
Fix — SQL
-- declare the cursor before you FETCH or CLOSE it
BEGIN;
DECLARE order_cursor CURSOR FOR SELECT g FROM generate_series(1, 3) AS g;
FETCH ALL FROM order_cursor;
CLOSE order_cursor;
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-19 (isolated lab, PostgreSQL 16.14)
Reviewed by
Verified against PostgreSQL 16.14 in an isolated lab environment
Audit status
reviewed