How to fix Duplicate cursor in PostgreSQL

PostgreSQLINTERMEDIATEMEDIUMUpdated Dec 27, 2025ยท 113 views

A duplicate cursor error (SQLSTATE 42P03) occurs when attempting to declare a cursor with a name that already exists in the current session. Close the existing cursor before redeclaring it.

Quick fix

Fixes 42P03

CLOSE cursor_name;
DECLARE cursor_name CURSOR FOR SELECT * FROM table_name;
  1. Close the existing cursor before redeclaring it
  2. Use unique cursor names for different queries
  3. Ensure proper cleanup in loops
  4. Handle cursor cleanup in exception blocks
postgresql โ€” error
CLOSE cursor_name;
DECLARE cursor_name CURSOR FOR SELECT * FROM table_name;
Duplicate cursor

What this error means

PostgreSQL maintains cursor names within a session scope. When you attempt to declare a cursor using DECLARE CURSOR or open a cursor in PL/pgSQL code, the database engine checks if a cursor with that name is already active. If it is, PostgreSQL raises error 42P03 to prevent ambiguity and conflicts. This error typically occurs in stored procedures or transactions when the same cursor name is reused without proper cleanup.

Typical symptoms

  • Error message: "ERROR: cursor already exists" or "Duplicate cursor"
  • Application fails when trying to declare or open a cursor with the same name twice
  • PL/pgSQL functions that loop through results fail on second iteration
  • Cursor-based operations in transactions fail unexpectedly

Common causes

  1. Attempting to declare a cursor with a name that is already open in the current session
  2. Reusing cursor names in loops without closing them first
  3. Multiple code paths in a function declaring the same cursor name without closing between calls
  4. Not handling cursor cleanup properly in error scenarios or exception handlers
  5. Forgetting to close a cursor before attempting to reopen it with the same name

How to fix "Duplicate cursor"

1Close the existing cursor before redeclaring it

Use the CLOSE statement to explicitly close an open cursor. This is the most direct fix when you need to reuse a cursor name:

sql
CLOSE cursor_name;
DECLARE cursor_name CURSOR FOR SELECT * FROM table_name;

In PL/pgSQL functions:

plpgsql
IF NOT FOUND THEN
  CLOSE my_cursor;
END IF;
2Use unique cursor names for different queries

If you have multiple cursors in the same function or transaction, give each one a distinct name:

plpgsql
DECLARE
  cursor_1 CURSOR FOR SELECT id FROM users;
  cursor_2 CURSOR FOR SELECT id FROM orders;
BEGIN
  OPEN cursor_1;
  OPEN cursor_2;
  -- Use both cursors
END;

This avoids the duplicate name issue entirely.

3Ensure proper cleanup in loops

When iterating with cursors in loops, always close the cursor before the next iteration if reusing the same name:

plpgsql
FOR i IN 1..10 LOOP
  IF i > 1 THEN
    CLOSE my_cursor;
  END IF;
  DECLARE my_cursor CURSOR FOR SELECT * FROM data WHERE id = i;
  OPEN my_cursor;
  -- Process cursor
END LOOP;

Better approach: use a different cursor name for each iteration or use REFCURSOR variables.

4Handle cursor cleanup in exception blocks

Ensure cursors are closed even when errors occur:

plpgsql
BEGIN
  DECLARE my_cursor CURSOR FOR SELECT * FROM users;
  OPEN my_cursor;
  -- Process cursor
EXCEPTION WHEN OTHERS THEN
  IF FOUND THEN
    CLOSE my_cursor;
  END IF;
  RAISE;
END;

This pattern ensures cleanup happens regardless of whether the operation succeeds.

5Use refcursor for dynamic cursor handling

For more complex scenarios, consider using REFCURSOR variables:

plpgsql
CREATE OR REPLACE FUNCTION get_data()
RETURNS refcursor AS $$
DECLARE
  curs refcursor;
BEGIN
  OPEN curs FOR SELECT * FROM users;
  RETURN curs;
END;
$$ LANGUAGE plpgsql;

REFCURSOR provides better control and automatic cleanup at transaction boundaries.

Advanced notes

PostgreSQL error code 42P03 falls under class 42 (Syntax Error or Access Rule Violation). Cursors are session-local unless created WITH HOLD, which allows them to persist across transaction boundaries. All cursors are implicitly closed at transaction end, so the duplicate cursor error typically occurs within a single transaction or stored procedure execution. In WITH HOLD cursors, the cursor persists until explicitly closed or the session ends. Understanding cursor scope and transaction boundaries is critical for avoiding this error in production code.

Frequently asked questions

What does "42P03" mean?
PostgreSQL maintains cursor names within a session scope. When you attempt to declare a cursor using DECLARE CURSOR or open a cursor in PL/pgSQL code, the database engine checks if a cursor with that name is already active. If it is, PostgreSQL raises error 42P03 to prevent ambiguity and conflicts.
How do I fix "42P03"?
A duplicate cursor error (SQLSTATE 42P03) occurs when attempting to declare a cursor with a name that already exists in the current session. Close the existing cursor before redeclaring it.
What causes "42P03"?
Attempting to declare a cursor with a name that is already open in the current session Reusing cursor names in loops without closing them first Multiple code paths in a function declaring the same cursor name without closing between calls
Is the "42P03" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading