42P03
Read PG 18 manual ↗duplicate_cursor
- SQLSTATE
- 42P03
- Condition name
- duplicate_cursor
- Class
- Syntax Error or Access Rule Violation
- Source macro
- ERRCODE_DUPLICATE_CURSOR
- Evidence
- Source path confirmed
English SQLSTATE atlas: authored explanations and source/runtime evidence are separate from the manual definitions. View source ↗
At a glance
42P03 (duplicate_cursor) reports a cursor/portal name collision, but the same SQLSTATE covers an ERROR, a replacement WARNING, and a PL/pgSQL-specific active-cursor ERROR. The caller and the CreatePortal options determine which behavior occurred.
Meaning
CreatePortal(name, allowDup, dupSilent) raises ERROR cursor "%s" already exists when allowDup is false. When allowDup is true, it can emit WARNING closing existing cursor "%s" unless dupSilent is set, then drops the old portal and creates the new one. PL/pgSQL takes a different branch: SPI_cursor_find detects an already active named cursor and raises ERROR cursor "%s" already in use.
Diagnosis
Record the exact name, source (SQL portal creation or PL/pgSQL OPEN), severity, and transaction state. For SQL, inspect portal creation/reuse and pg_cursors where that view exposes the portal; for PL/pgSQL, inspect the cursor variable and the OPEN/CLOSE flow. The allowDup replacement branch is not evidence that a user-level duplicate declaration always warns, and the PL/pgSQL branch is not the portal-manager replacement path.
Response
For an ERROR from a non-replacing portal path, close the old portal or choose a name whose transaction lifetime is correct. A WARNING replacement path already closes the old portal, so the application must verify that replacement is intended rather than treating the warning as a failed close. For PL/pgSQL, close the named cursor before reopening it or use a distinct cursor variable/name. Only ERROR paths require explicit-transaction recovery with a savepoint rollback or transaction rollback; reconnecting can hide pool ownership problems.
Messages
Representative 18.6 messages are:
| Path | Severity | Primary |
|---|---|---|
CreatePortal(..., allowDup=false, ...) |
ERROR |
cursor "%s" already exists |
CreatePortal(..., allowDup=true, dupSilent=false) |
WARNING |
closing existing cursor "%s" |
| PL/pgSQL named cursor already found | ERROR |
cursor "%s" already in use |
The %s value is dynamic; no concrete cursor name is claimed.
Versions
From 7.4 through 18.6 and 19beta3; the catalogue range is not a precise introduction claim. The selected portal-manager and PL/pgSQL branches are fixed 18.6 source paths, and runtime was not run.
Sources
-
src.errcodes.42P03.18.6—src/backend/utils/errcodes.txtline 378, fixed at724edf9bde9d356724ad384a2e196edc3c9f80f7; SHA-2566e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba(source). -
src.call.42P03.800a8278cf453417f5af6d6e—src/backend/utils/mmgr/portalmem.clines 185-187, fixed at724edf9bde9d356724ad384a2e196edc3c9f80f7; SHA-2568e29a302a7837316765acc798f9ff6eb22a330e8098a02794cd4d683601d3b04(source). src.call.42P03.208bdd3b576b5021fb35916d—src/backend/utils/mmgr/portalmem.clines 189-192, fixed at724edf9bde9d356724ad384a2e196edc3c9f80f7; SHA-2568e29a302a7837316765acc798f9ff6eb22a330e8098a02794cd4d683601d3b04(source).src.call.42P03.06c0580b43488eece2de1973—src/pl/plpgsql/src/pl_exec.clines 2895-2897, fixed at724edf9bde9d356724ad384a2e196edc3c9f80f7; SHA-2560df3c70a6bccf6dddf443fb99e152a16a67009827c44a820597e98e585cb8b20(source).src.calls.REL_18_6.42P03— resolved core call groups; SHA-2569ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf.authored evidence— source claims, message roles, and runtime boundary.
Source evidence
Evidence belongs to the frozen source and runtime versions listed here. It is not a runtime verification of the selected manual version.
42P03 is the duplicate_cursor condition in Class 42.
Method: Read fixed REL_18_6 errcodes.txt and locked facts.
Limits: Identity does not enumerate all source branches or client failures.
CreatePortal(name, allowDup, dupSilent) reports ERROR `cursor "%s" already exists` when allowDup is false, can report WARNING `closing existing cursor "%s"` before dropping a duplicate when allowDup is true and dupSilent is false, and PL/pgSQL separately reports ERROR `cursor "%s" already in use` when SPI_cursor_find finds an active named cursor.
Method: Read complete resolved REL_18_6 report groups and message roles.
Limits: Representative confirmed core paths only; not exhaustive historical or extension coverage.
src.call.42P03.800a8278cf453417f5af6d6e src.call.42P03.208bdd3b576b5021fb35916d src.call.42P03.06c0580b43488eece2de1973
From 7.4 through 18.6 and 19beta3; the selected portal-manager and PL/pgSQL branches are fixed 18.6 source paths and runtime was not run.
Method: Read locked catalogue facts and definition snapshots.
Limits: First observed release is a lower bound, not precise behavioral introduction.
- src/backend/utils/errcodes.txt · REL_18_6 · line 378
724edf9bde9d356724ad384a2e196edc3c9f80f7 - src/backend/utils/mmgr/portalmem.c · REL_18_6 · lines 185-187
724edf9bde9d356724ad384a2e196edc3c9f80f7 - src/backend/utils/mmgr/portalmem.c · REL_18_6 · lines 189-192
724edf9bde9d356724ad384a2e196edc3c9f80f7 - src/pl/plpgsql/src/pl_exec.c · REL_18_6 · lines 2895-2897
724edf9bde9d356724ad384a2e196edc3c9f80f7 raw/calls/REL_18_6.jsonl· ·
Message templates
explicit ERROR · message.variant-1
Primary
cursor "%s" already exists
Placeholders remain dynamic source fields; no concrete runtime value is claimed.
explicit WARNING · message.variant-2
Primary
closing existing cursor "%s"
Placeholders remain dynamic source fields; no concrete runtime value is claimed.
explicit ERROR · message.variant-3
Primary
cursor "%s" already in use
Placeholders remain dynamic source fields; no concrete runtime value is claimed.
Reproduction & repair cases
No reproduction case is attached to this condition.
Recorded runtime evidence
No runtime observation is attached to this entry.
Definition snapshot: english-manuals:03b89752cecd035e156fcc511bc… · English manual source