# 42P02 — Undefined parameter

> PostgreSQL SQLSTATE 42P02: Undefined parameter (undefined_parameter), source-backed diagnosis and recovery guidance.
---

# 42P02 — Undefined parameter

## At a glance {#at-a-glance}

`42P02` (**undefined_parameter**) is a parse-time `ERROR` because a positional marker such as `$1` is outside the parameter set known to parse analysis. It differs from a Bind-message count violation (`08P01`) and from `42P08`, where a known parameter cannot receive a consistent type.

<!-- BEGIN SQLSTATE FACTS: generated by scripts/generate.py; do not edit -->

| Field | Value |
| --- | --- |
| SQLSTATE | `42P02` |
| Condition | `undefined_parameter` |
| Status | `active` |
| Known present by | `7.4` |
| Locked snapshots | `9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3` |
| Macros | `ERRCODE_UNDEFINED_PARAMETER` |
| Aliases | `—` |

<!-- source facts: data/errcodes/42P02.json -->
<!-- END SQLSTATE FACTS -->

## Meaning {#meaning}

The fixed-parameter hook rejects a parameter number outside the declared array or with an invalid type. The variable-parameter hook can grow its array while parsing, but its resolution checks still reject an out-of-range parameter. The generic parser hook reports the same primary when no hook resolves the marker. All selected branches attach parser position and use the dynamic number in `there is no parameter $%d`; this is about SQL `ParamRef` markers, not a missing column or PL/pgSQL variable.

The extended-query boundary is separate: `exec_bind_message` checks the number of parameter formats and values against the prepared statement and reports `08P01` for a count mismatch, including `bind message supplies %d parameters, but prepared statement "%s" requires %d`. A value-count or format-count failure during Bind therefore should not be relabeled as `42P02`.

## Diagnosis {#diagnosis}

Capture the SQL text, parser position, parameter number, and protocol phase. During Parse/parse analysis, compare every `$n` with the declared fixed or variable parameter set. During extended-query Bind, compare the format count and value count with the prepared statement and route a mismatch to `08P01`; a missing SQL marker mapping is a different problem. Keep `42P08` for a parameter that exists but receives incompatible type deductions.

## Response {#response}

Fix the SQL placeholder numbering or the Parse parameter declaration. In the Bind phase, send exactly the prepared statement's required parameter count and a compatible format-code count; do not try to cure a count mismatch with a cast. For a genuine missing marker, add the intended parameter or use a deliberate literal/default. If the `ERROR` occurred inside an explicit transaction, roll back to a suitable savepoint or roll back the transaction before retrying; no runtime recovery is claimed here.

## Messages {#messages}

The selected parser groups are explicit `ERROR` with `there is no parameter $%d`; `%d` is the dynamic referenced parameter number. The separate fixed 18.6 Bind guards are explicit `08P01`, with `bind message has %d parameter formats but %d parameters` or `bind message supplies %d parameters, but prepared statement "%s" requires %d`.

## Versions {#versions}

From the locked 7.4 lower bound through 18.6 and 19beta3; that is a catalogue range, not a runtime comparison. The selected parser and Bind branches are fixed 18.6 source paths; no client bind case was run.

## Related {#related}

- [`42P08`](../42p08/)
- [`42P09`](../42p09/)
- [`08P01`](../08p01/)
- [`42601`](../42601/)

## Sources {#sources}
- `src.errcodes.42P02.18.6` — `src/backend/utils/errcodes.txt` line 375, fixed at `724edf9bde9d356724ad384a2e196edc3c9f80f7`; SHA-256 `6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba` ([source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt#L375)).

- `src.call.42P02.81f0048a16f439569ce3a4ba` — `src/backend/parser/parse_expr.c` lines 899-902, fixed at `724edf9bde9d356724ad384a2e196edc3c9f80f7`; SHA-256 `63c37770872a08978f931c31f801666a08e3bc8e51c2c65ff60151a1d139d55b` ([source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/parser/parse_expr.c#L899-L902)).
- `src.call.42P02.73515542f469d69893fd5fb8` — `src/backend/parser/parse_param.c` lines 109-112, fixed at `724edf9bde9d356724ad384a2e196edc3c9f80f7`; SHA-256 `4aab2ecc770fcda619b26ac12beaf7e527542b56f55eb45879b72e92442e8a28` ([source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/parser/parse_param.c#L109-L112)).
- `src.call.42P02.671f865f9d428e0ab2a78347` — `src/backend/parser/parse_param.c` lines 203-206, fixed at `724edf9bde9d356724ad384a2e196edc3c9f80f7`; SHA-256 `4aab2ecc770fcda619b26ac12beaf7e527542b56f55eb45879b72e92442e8a28` ([source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/parser/parse_param.c#L203-L206)).
- `src.call.42P02.bind-contract` — `src/backend/tcop/postgres.c` lines 1718-1731, fixed at `724edf9bde9d356724ad384a2e196edc3c9f80f7`; SHA-256 `9fb62275b1badf94d01ab351337b60410cd9b3ab1fe63fa9f23d6d2185a21061` ([source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/tcop/postgres.c#L1718-L1731)).
- `src.calls.REL_18_6.42P02` — resolved core call groups; SHA-256 `9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf`.
- [`authored evidence`](../data/evidence/42p02.json) — source claims, message roles, and runtime boundary.
