34000 — invalid_cursor_name
34000 means that a cursor or portal name cannot be resolved in the current backend session. A cursor that was closed, declared on another pooled connection, or ended with its transaction is not the same resource as a cursor with a bad position (24000).
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
- Invalid Cursor Name
- condition name
- invalid_cursor_name
- lang
- en
- sqlstate
- 34000
Definition PG 18
34000 — invalid_cursor_name
At a glance {#at-a-glance}
34000 means that a cursor or portal name cannot be resolved in the current backend session. A cursor that was closed, declared on another pooled connection, or ended with its transaction is not the same resource as a cursor with a bad position (24000).
Meaning {#meaning}
The executor's portal path reports cursor "%s" does not exist when FETCH cannot find the named portal. Cursor names are tied to a backend session, and ordinary cursors are tied to a transaction unless declared with an appropriate hold option. A pool checkout therefore must keep declaration and use on the same connection and within the intended transaction boundary.
Diagnosis {#diagnosis}
Record SQLSTATE, the dynamic cursor name, backend PID, and transaction status. Check the application path for an earlier CLOSE, an implicit commit, a connection return to the pool, or a different session. pg_cursors and the server-side session identity can help when the diagnosis runs on the same backend; a new connection cannot inspect or fetch a cursor owned by the old one.
Response {#response}
For an explicit block, rollback after the failed FETCH before issuing more commands. Re-declare the cursor on the same session, or deliberately redesign the workflow to materialize keys/results when work must cross pool checkouts. Use a holdable cursor only when its commit-survival semantics are intended; it does not make a cursor portable between sessions.
Messages {#messages}
The selected core path uses cursor "%s" does not exist; protocol and PL/pgSQL paths can use portal "%s" or the same cursor wording. The name is dynamic, so use the SQLSTATE and diagnostic fields rather than a full-message equality check across versions and callers.
Representative case {#case}
The shared registry in verify/cases/34000/snippets.json (SHA-256 ad5b519e8ca30fd2636b1d0bace32dc18558cccc7b9d360081c27b12a1405f08) declares and closes a cursor, proves the missing-FETCH error, rolls back, and recreates it in the same session. See the public case export and structured evidence.
BEGIN;
DECLARE cursor_name CURSOR FOR SELECT 1;
CLOSE cursor_name;
FETCH cursor_name;
ROLLBACK;
BEGIN;
DECLARE cursor_name CURSOR FOR SELECT 1;
FETCH cursor_name;
CLOSE cursor_name;
COMMIT;
The runner substitutes a unique cursor name. The first FETCH is intentionally after CLOSE; the second FETCH occurs after a new BEGIN and declaration, so the successful row proves lifecycle repair rather than a client-side mock.
The selected case observed 34000 on PostgreSQL 18.6 and 10.21 after closing a named cursor and attempting FETCH. The failed block reached INERROR; rollback followed by a new declaration, fetch, close, and commit returned the session to IDLE.
Versions {#versions}
The locked catalogue records this condition across the formal snapshots. 18.6 and 10.23 source scans both contain the portal and PL/pgSQL paths; the selected runtime case observes the same SQLSTATE on 18.6 and 10.21, while exact source line and caller wording vary.
Related {#related}
Compare 24000 invalid cursor state for a cursor that exists but is not positioned, and 26000 invalid prepared statement name for another session-local resource.
Sources {#sources}
src.errcodes.18.6(SHA-2566e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba)src.portalcmds.18.6(SHA-256e71c5bdb2da67771fb5f42f18b823e8af3ee6c31d5314e97a47ad18f7788bf35)DECLARE documentation· local call scansrc.calls.REL_18_6(SHA-2569ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf)
Compare versions
SQLSTATE evidence and recorded runtime versions
cases · cursor_lifecycle_recovery
{
"assertions": [
"SQLSTATE is 34000",
"The missing cursor diagnostic is preserved",
"The failed block recovers through ROLLBACK",
"A recreated cursor can FETCH and COMMIT"
],
"case_id": "cursor_lifecycle_recovery",
"cleanup": "Drop the case schema with an owner connection.",
"has_snippet": true,
"position": 0,
"preconditions": [
"A runner-owned disposable target is provisioned."
],
"repair": "Keep cursor use on the declaring backend session and respect its transaction lifetime; after an error, roll back before recreating it.",
"trigger": "Declare and close a named cursor, attempt to use it again, then recreate it in a new explicit transaction on the same session.",
"versions": [
"10",
"18"
]
}claims · identity
{
"claim_id": "identity",
"limits": "The same SQLSTATE covers several cursor/portal-facing paths.",
"method": "Read the fixed errcodes.txt row and macro mapping.",
"position": 0,
"runtime": [],
"sources": [
"src.errcodes.18.6"
],
"statement": "34000 is the invalid_cursor_name condition in Class 34 and shares the undefined-cursor alias."
}claims · portal-path
{
"claim_id": "portal-path",
"limits": "Other callers use portal or cursor wording; the name is dynamic.",
"method": "Trace ERRCODE_UNDEFINED_CURSOR in portalcmds.c.",
"position": 1,
"runtime": [],
"sources": [
"src.portalcmds.18.6",
"src.calls.REL_18_6"
],
"statement": "PerformPortalFetch emits cursor \"%s\" does not exist when the named portal is absent."
}claims · lifecycle
{
"claim_id": "lifecycle",
"limits": "Holdable cursors and client-side cursor abstractions have additional rules.",
"method": "Compare DECLARE cursor lifecycle with the explicit same-session registry case.",
"position": 2,
"runtime": [],
"sources": [
"doc.declare.18.6"
],
"statement": "A named cursor belongs to its backend session and transaction lifecycle; closing it or losing its transaction makes a later FETCH invalid."
}claims · runtime
{
"claim_id": "runtime",
"limits": "This covers the selected mechanism only, not all source callers or all driver/pool behavior.",
"method": "Read the selected runner summaries and raw outputs tied to the shared snippet registry.",
"position": 3,
"runtime": [],
"sources": [
"runtime.34000-batch34-20260909.latest",
"runtime.34000-batch34-20260909.pg10"
],
"statement": "The selected 34000 case passed on PostgreSQL 18.6 and 10.21 with the structured SQLSTATE, transaction-state, and repair assertions recorded in the runtime entries."
}messages · message.cursor-missing
{
"limits": "The portal protocol path uses portal \"%s\" does not exist.",
"message_id": "message.cursor-missing",
"path": "",
"position": 0,
"raw": {
"id": "message.cursor-missing",
"limits": "The portal protocol path uses portal \"%s\" does not exist.",
"primary_template": "cursor \"%s\" does not exist",
"severity_source": "ERROR",
"sources": [
"src.portalcmds.18.6"
],
"sqlstate": "34000"
},
"severity": "ERROR",
"sources": [
"src.portalcmds.18.6"
],
"templates": [
{
"kind": "primary",
"literal": "cursor \" \" does not exist",
"position": 0,
"role": "",
"template": "cursor \"%s\" does not exist"
}
]
}runtimes · runtime.34000-batch34-20260909.latest · 18.6 (Homebrew) · passed
{
"cases": [
"cursor_lifecycle_recovery"
],
"limits": "",
"position": 0,
"raw": {
"case_manifest": {
"path": "verify/cases/34000/cases.json",
"sha256": "72347c5c8f1ccfaa18aced582e9ff5bf0f968eff0547c9a8f6521ed7fa3adb47"
},
"cases": [
"cursor_lifecycle_recovery"
],
"id": "runtime.34000-batch34-20260909.latest",
"observed": {
"connection_autocommit": true,
"primary": "cursor \"case_cursor_aa951a82\" does not exist",
"repair": {
"fetched_row": [
1
]
},
"severity": "ERROR",
"sqlstate": "34000",
"statuses": {
"after_error": "INERROR",
"after_repair": "IDLE",
"after_rollback": "IDLE"
}
},
"raw": "verify/results/34000-batch34-20260909/latest/raw.jsonl",
"raw_sha256": "91c68dc423bfd301219891f250d584678c5300e1376c9fb6d75731b169d5f560",
"run_id": "34000-batch34-20260909",
"server_version": "18.6 (Homebrew)",
"snippet_registry": {
"path": "verify/cases/34000/snippets.json",
"sha256": "ad5b519e8ca30fd2636b1d0bace32dc18558cccc7b9d360081c27b12a1405f08"
},
"status": "passed",
"summary": "verify/results/34000-batch34-20260909/latest/summary.json",
"summary_sha256": "113822682213d49699a80ba97c2d3bad78a795790edfd32e7dbc362d16456e3e",
"target": "latest"
},
"run_id": "34000-batch34-20260909",
"runtime_id": "runtime.34000-batch34-20260909.latest",
"server_version": "18.6 (Homebrew)",
"status": "passed",
"target": "latest"
}runtimes · runtime.34000-batch34-20260909.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · passed
{
"cases": [
"cursor_lifecycle_recovery"
],
"limits": "",
"position": 1,
"raw": {
"case_manifest": {
"path": "verify/cases/34000/cases.json",
"sha256": "72347c5c8f1ccfaa18aced582e9ff5bf0f968eff0547c9a8f6521ed7fa3adb47"
},
"cases": [
"cursor_lifecycle_recovery"
],
"id": "runtime.34000-batch34-20260909.pg10",
"observed": {
"connection_autocommit": true,
"primary": "cursor \"case_cursor_d0bb43e5\" does not exist",
"repair": {
"fetched_row": [
1
]
},
"severity": "ERROR",
"sqlstate": "34000",
"statuses": {
"after_error": "INERROR",
"after_repair": "IDLE",
"after_rollback": "IDLE"
}
},
"raw": "verify/results/34000-batch34-20260909/pg10/raw.jsonl",
"raw_sha256": "1089cf85363624dcf5430744047b9dfde4760d763ebe10d5ed148047f9bb7c5c",
"run_id": "34000-batch34-20260909",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"snippet_registry": {
"path": "verify/cases/34000/snippets.json",
"sha256": "ad5b519e8ca30fd2636b1d0bace32dc18558cccc7b9d360081c27b12a1405f08"
},
"status": "passed",
"summary": "verify/results/34000-batch34-20260909/pg10/summary.json",
"summary_sha256": "5c73ff2695864619e3771294e896ec2704bb4fae8e2b16d72aedf220063c2c6a",
"target": "pg10"
},
"run_id": "34000-batch34-20260909",
"runtime_id": "runtime.34000-batch34-20260909.pg10",
"server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
"status": "passed",
"target": "pg10"
}sources · src.errcodes.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/utils/errcodes.txt",
"position": 0,
"sha256": "6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba",
"source_id": "src.errcodes.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt"
}sources · src.calls.REL_18_6
{
"commit": "",
"docs_url": "",
"kind": "local_artifact",
"location": "",
"path": "raw/calls/REL_18_6.jsonl",
"position": 1,
"sha256": "9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf",
"source_id": "src.calls.REL_18_6",
"tag": "",
"url": ""
}sources · src.portalcmds.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "",
"kind": "upstream_source",
"location": "",
"path": "src/backend/commands/portalcmds.c",
"position": 2,
"sha256": "e71c5bdb2da67771fb5f42f18b823e8af3ee6c31d5314e97a47ad18f7788bf35",
"source_id": "src.portalcmds.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/commands/portalcmds.c#L197-L199"
}sources · doc.declare.18.6
{
"commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
"docs_url": "https://www.postgresql.org/docs/18/sql-declare.html",
"kind": "upstream_source",
"location": "",
"path": "doc/src/sgml/ref/declare.sgml",
"position": 3,
"sha256": "f1d72befb9a989aa32123560aea784a8bccfcb3d3930804a101d8245e5a3cc95",
"source_id": "doc.declare.18.6",
"tag": "REL_18_6",
"url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/doc/src/sgml/ref/declare.sgml"
}Source references
Full definition and evidence JSON
Definition sources
center · PostgreSQL 18 · english-manuals:44fb2ceedd823afc8b65a568c17489e06450fe8b98537be62250077c30cf53b7
Text language: en · english-manuals:44fb2ceedd823afc8b65a568c17489e06450fe8b98537be62250077c30cf53b7