↑↓ select↵ open⌫ change scopeOpen full search

PG.CENTER connects PostgreSQL documentation, reference, and ecosystem knowledge. Maintained by Pigsty.

Wiki / SQLSTATE

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-256 6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba)
  • src.portalcmds.18.6 (SHA-256 e71c5bdb2da67771fb5f42f18b823e8af3ee6c31d5314e97a47ad18f7788bf35)
  • DECLARE documentation · local call scan src.calls.REL_18_6 (SHA-256 9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf)

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