How to fix Invalid cursor name in PostgreSQL

PostgreSQLINTERMEDIATEMEDIUMUpdated Dec 29, 2025· 118 views

PostgreSQL error 34000 occurs when you reference a cursor that does not exist, has not been declared, or is not accessible in the current scope. Ensure the cursor is declared before use and accessed within the same transaction where it was created.

Quick fix

Fixes 34000

BEGIN;
  DECLARE my_cursor CURSOR FOR SELECT * FROM users;
  FETCH FROM my_cursor;  -- Now valid
END;
  1. Verify the cursor is declared before use
  2. Check cursor name spelling and case
  3. Keep cursor and fetch in same transaction
  4. In PL/pgSQL, declare cursor at block level
postgresql — error
BEGIN;
DECLARE my_cursor CURSOR FOR SELECT * FROM users;
FETCH FROM my_cursor; -- Now valid
END;
Invalid cursor name

What this error means

Error 34000 indicates that PostgreSQL encountered a reference to a cursor name that does not exist or is not accessible in the current context. In PostgreSQL, cursors are transaction-specific objects that must be explicitly declared with the DECLARE statement before they can be used. When you attempt to FETCH from, MOVE on, or CLOSE a cursor that was never declared, has already been closed, or is outside the scope of the current block or transaction, PostgreSQL raises error 34000. This error commonly occurs in PL/pgSQL functions, stored procedures, and multi-step SQL transactions where cursor lifecycle management is not properly handled.

Typical symptoms

  • FETCH command fails with "cursor does not exist" message
  • MOVE command on cursor produces invalid cursor name error
  • CLOSE command fails for non-existent cursor
  • Cursor reference in PL/pgSQL block fails after transaction commit
  • Function returns "cursor not found" when called multiple times

Common causes

  1. Cursor is referenced before it has been declared with DECLARE statement
  2. Cursor name is misspelled or uses incorrect case sensitivity in variable reference
  3. Cursor was declared in a different transaction or PL/pgSQL block and is no longer in scope
  4. Cursor was already closed with CLOSE statement and you attempt to use it again
  5. Cursor was declared inside a transaction that was committed, and you try to fetch in a new transaction
  6. In application code, the cursor object reference was lost or not passed correctly between function calls

How to fix "Invalid cursor name"

1Verify the cursor is declared before use

Ensure that the cursor is declared with the DECLARE statement before any FETCH, MOVE, or CLOSE operations:

sql
BEGIN;
  DECLARE my_cursor CURSOR FOR SELECT * FROM users;
  FETCH FROM my_cursor;  -- Now valid
END;

If the cursor is referenced before DECLARE, move the DECLARE statement to the beginning of the transaction or block.

2Check cursor name spelling and case

PostgreSQL identifiers are case-insensitive by default unless quoted. If you declare a cursor with unquoted name, use the same unquoted name in FETCH/MOVE/CLOSE commands:

sql
-- Declaration
DECLARE my_cursor CURSOR FOR SELECT * FROM users;
-- Use lowercase (folded to my_cursor internally)
FETCH FROM my_cursor;  -- Correct
FETCH FROM MY_CURSOR;  -- Also correct (case-folded)

-- If quoted, must match exactly:
DECLARE "MyCursor" CURSOR FOR SELECT * FROM users;
FETCH FROM "MyCursor";  -- Must use exact case
3Keep cursor and fetch in same transaction

Cursors exist only within the transaction where they were declared. Do not commit or rollback the transaction after declaring a cursor if you plan to fetch from it:

sql
-- Correct: All in one transaction
BEGIN;
  DECLARE my_cursor CURSOR FOR SELECT * FROM users;
  FETCH FROM my_cursor;
COMMIT;

-- Wrong: Cursor lost after first transaction
BEGIN;
  DECLARE my_cursor CURSOR FOR SELECT * FROM users;
COMMIT;  -- Cursor closed here
FETCH FROM my_cursor;  -- Error: cursor not found
4In PL/pgSQL, declare cursor at block level

In PL/pgSQL functions and blocks, cursors must be declared in the DECLARE section or use refcursor variables:

sql
DO $$
DECLARE
  my_cursor CURSOR FOR SELECT * FROM users;
  rec RECORD;
BEGIN
  OPEN my_cursor;
  LOOP
    FETCH my_cursor INTO rec;
    EXIT WHEN NOT FOUND;
    RAISE NOTICE '%', rec;
  END LOOP;
  CLOSE my_cursor;
END $$;

Note: Use OPEN instead of just declaring, and ensure CLOSE is called before the function ends.

5For refcursor, ensure proper scope in functions

If passing refcursor as a function parameter, ensure the cursor is opened in the calling context:

sql
CREATE FUNCTION fetch_users(cur REFCURSOR) RETURNS SETOF RECORD AS $$
BEGIN
  RETURN QUERY FETCH ALL FROM cur;  -- cur must be opened by caller
END;
$$ LANGUAGE plpgsql;

-- Caller must open cursor before calling function
BEGIN;
  DECLARE my_cursor CURSOR FOR SELECT * FROM users;
  SELECT * FROM fetch_users(my_cursor);
COMMIT;

Advanced notes

Cursor Lifecycle and Transactions: PostgreSQL cursors are tightly bound to their declaring transaction. Unlike some databases that support scrollable or persistent cursors, PostgreSQL cursors are ephemeral—they exist only during the transaction that created them. When using application connection pooling, be aware that each application statement may run in a different connection with different transaction context. Always fetch cursor results within the same logical transaction. In PL/pgSQL, the distinction between DECLARE (for local cursors) and REFCURSOR (for return values) is important: local cursors are automatically closed when the function exits, while refcursors can be returned to the caller but must still be used before the original transaction commits. For long-running operations across multiple client requests, consider fetching all results into a temporary table or application array rather than relying on cursor state across requests.

Frequently asked questions

What does "34000" mean?
Error 34000 indicates that PostgreSQL encountered a reference to a cursor name that does not exist or is not accessible in the current context. In PostgreSQL, cursors are transaction-specific objects that must be explicitly declared with the DECLARE statement before they can be used. When you attempt to FETCH from, MOVE on, or CLOSE a cursor that was never declared, has already been closed, or is outside the scope of the current block or transaction, PostgreSQL raises error 34000.
How do I fix "34000"?
PostgreSQL error 34000 occurs when you reference a cursor that does not exist, has not been declared, or is not accessible in the current scope. Ensure the cursor is declared before use and accessed within the same transaction where it was created.
What causes "34000"?
Cursor is referenced before it has been declared with DECLARE statement Cursor name is misspelled or uses incorrect case sensitivity in variable reference Cursor was declared in a different transaction or PL/pgSQL block and is no longer in scope
Is the "34000" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading