How to fix Duplicate cursor in PostgreSQL
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;- Close the existing cursor before redeclaring it
- Use unique cursor names for different queries
- Ensure proper cleanup in loops
- Handle cursor cleanup in exception blocks
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
- 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
- Not handling cursor cleanup properly in error scenarios or exception handlers
- Forgetting to close a cursor before attempting to reopen it with the same name
How to fix "Duplicate cursor"
Use the CLOSE statement to explicitly close an open cursor. This is the most direct fix when you need to reuse a cursor name:
CLOSE cursor_name;
DECLARE cursor_name CURSOR FOR SELECT * FROM table_name;In PL/pgSQL functions:
IF NOT FOUND THEN
CLOSE my_cursor;
END IF;If you have multiple cursors in the same function or transaction, give each one a distinct name:
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.
When iterating with cursors in loops, always close the cursor before the next iteration if reusing the same name:
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.
Ensure cursors are closed even when errors occur:
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.
For more complex scenarios, consider using REFCURSOR variables:
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
- ๐PostgreSQL Official Documentation
- ๐PostgreSQL Error Codes Appendix(Official Docs)
- ๐PostgreSQL DECLARE Statement(Official Docs)
- ๐PostgreSQL PL/pgSQL Cursors(Official Docs)