42P03 — Duplicate cursor
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.
English manual coverage begins with PostgreSQL 8.1. Source history and runtime observations have their own recorded version boundaries.
Reading PG 18·Select a recorded version
- aliases
- Unknown
- class name
- Syntax Error or Access Rule Violation
- condition name
- duplicate_cursor
- lang
- en
- sqlstate
- 42P03
Definition PG 18
42P03 — Duplicate cursor
At a glance {#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 {#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 {#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 {#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 {#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 {#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.
Related {#related}
Sources {#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.
Compare versions
SQLSTATE evidence and recorded runtime versions
claims · identity.class-and-condition
{
"claim_id": "identity.class-and-condition",
"limits": "Identity does not enumerate all source branches or client failures.",
"method": "Read fixed REL_18_6 errcodes.txt and locked facts.",
"position": 0,
"runtime": [],
"sources": [
"src.errcodes.42P03.18.6"
],
"statement": "42P03 is the duplicate_cursor condition in Class 42."
}claims · mechanism.selected-source-path
{
"claim_id": "mechanism.selected-source-path",
"limits": "Representative confirmed core paths only; not exhaustive historical or extension coverage.",
"method": "Read complete resolved REL_18_6 report groups and message roles.",
"position": 1,
"runtime": [],
"sources": [
"src.call.42P03.800a8278cf453417f5af6d6e",
"src.call.42P03.208bdd3b576b5021fb35916d",
"src.call.42P03.06c0580b43488eece2de1973"
],
"statement": "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."
}claims · versions.catalogue-boundary
{
"claim_id": "versions.catalogue-boundary",
"limits": "First observed release is a lower bound, not precise behavioral introduction.",
"method": "Read locked catalogue facts and definition snapshots.",
"position": 2,
"runtime": [],
"sources": [
"src.errcodes.42P03.18.6"
],
"statement": "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."
}messages · message.variant-1
{
"limits": "Placeholders remain dynamic source fields; no concrete runtime value is claimed.",
"message_id": "message.variant-1",
"path": "",
"position": 0,
"raw": {
"detail_templates": [],
"hint_templates": [],
"id": "message.variant-1",
"limits": "Placeholders remain dynamic source fields; no concrete runtime value is claimed.",
"primary_template": "cursor \"%s\" already exists",
"roles": [
{
"role": "errmsg",
"template": "cursor \"%s\" already exists"
}
],
"severity_source": "explicit ERROR",
"sources": [
"src.call.42P03.800a8278cf453417f5af6d6e"
],
"sqlstate": "42P03"
},
"severity": "explicit ERROR",
"sources": [
"src.call.42P03.800a8278cf453417f5af6d6e"
],
"templates": [
{
"kind": "primary",
"literal": "cursor \" \" already exists",
"position": 0,
"role": "",
"template": "cursor \"%s\" already exists"
}
]
}messages · message.variant-2
{
"limits": "Placeholders remain dynamic source fields; no concrete runtime value is claimed.",
"message_id": "message.variant-2",
"path": "",
"position": 1,
"raw": {
"detail_templates": [],
"hint_templates": [],
"id": "message.variant-2",
"limits": "Placeholders remain dynamic source fields; no concrete runtime value is claimed.",
"primary_template": "closing existing cursor \"%s\"",
"roles": [
{
"role": "errmsg",
"template": "closing existing cursor \"%s\""
}
],
"severity_source": "explicit WARNING",
"sources": [
"src.call.42P03.208bdd3b576b5021fb35916d"
],
"sqlstate": "42P03"
},
"severity": "explicit WARNING",
"sources": [
"src.call.42P03.208bdd3b576b5021fb35916d"
],
"templates": [
{
"kind": "primary",
"literal": "closing existing cursor \" \"",
"position": 0,
"role": "",
"template": "closing existing cursor \"%s\""
}
]
}messages · message.variant-3
{
"limits": "Placeholders remain dynamic source fields; no concrete runtime value is claimed.",
"message_id": "message.variant-3",
"path": "",
"position": 2,
"raw": {
"detail_templates": [],
"hint_templates": [],
"id": "message.variant-3",
"limits": "Placeholders remain dynamic source fields; no concrete runtime value is claimed.",
"primary_template": "cursor \"%s\" already in use",
"roles": [
{
"role": "errmsg",
"template": "cursor \"%s\" already in use"
}
],
"severity_source": "explicit ERROR",
"sources": [
"src.call.42P03.06c0580b43488eece2de1973"
],
"sqlstate": "42P03"
},
"severity": "explicit ERROR",
"sources": [
"src.call.42P03.06c0580b43488eece2de1973"
],
"templates": [
{
"kind": "primary",
"literal": "cursor \" \" already in use",
"position": 0,
"role": "",
"template": "cursor \"%s\" already in use"
}
]
}sources · src.errcodes.42P03.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "line 378",
"path": "src/backend/utils/errcodes.txt",
"position": 0,
"sha256": "6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba",
"source_id": "src.errcodes.42P03.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt#L378"
}sources · src.call.42P03.800a8278cf453417f5af6d6e
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "lines 185-187",
"path": "src/backend/utils/mmgr/portalmem.c",
"position": 1,
"sha256": "8e29a302a7837316765acc798f9ff6eb22a330e8098a02794cd4d683601d3b04",
"source_id": "src.call.42P03.800a8278cf453417f5af6d6e",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/mmgr/portalmem.c#L185-L187"
}sources · src.call.42P03.208bdd3b576b5021fb35916d
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "lines 189-192",
"path": "src/backend/utils/mmgr/portalmem.c",
"position": 2,
"sha256": "8e29a302a7837316765acc798f9ff6eb22a330e8098a02794cd4d683601d3b04",
"source_id": "src.call.42P03.208bdd3b576b5021fb35916d",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/mmgr/portalmem.c#L189-L192"
}sources · src.call.42P03.06c0580b43488eece2de1973
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "lines 2895-2897",
"path": "src/pl/plpgsql/src/pl_exec.c",
"position": 3,
"sha256": "0df3c70a6bccf6dddf443fb99e152a16a67009827c44a820597e98e585cb8b20",
"source_id": "src.call.42P03.06c0580b43488eece2de1973",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/pl/plpgsql/src/pl_exec.c#L2895-L2897"
}sources · src.calls.REL_18_6.42P03
{
"commit": "",
"docs_url": "",
"kind": "local_artifact",
"location": "",
"path": "raw/calls/REL_18_6.jsonl",
"position": 4,
"sha256": "9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf",
"source_id": "src.calls.REL_18_6.42P03",
"tag": "",
"url": ""
}Source references
Full definition and evidence JSON
Definition sources
center · PostgreSQL 18 · english-manuals:d27355120217f732026b1e5ecc24092c4ae150ad963e5e9c2bd50b97943bd1f3
Text language: en · english-manuals:d27355120217f732026b1e5ecc24092c4ae150ad963e5e9c2bd50b97943bd1f3