# 22P02 — Invalid text representation

> PostgreSQL SQLSTATE 22P02: Invalid text representation (invalid_text_representation), source-backed diagnosis and recovery guidance.
---

# 22P02 — Invalid text representation

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

`22P02` means a text input routine cannot interpret a value as the requested type. This page selects the ordinary integer input path and also marks the COPY/text boundary; COPY, enum, extension, and contrib callers can use different primary messages.

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

| Field | Value |
| --- | --- |
| SQLSTATE | `22P02` |
| Condition | `invalid_text_representation` |
| 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_INVALID_TEXT_REPRESENTATION` |
| Aliases | `—` |

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

## Meaning {#meaning}

For a cast, assignment, or text `COPY` field, the destination type's input routine decides whether text is valid. PostgreSQL 18.6 emits `invalid input syntax for type integer: "%s"`, while the locked PostgreSQL 10.23 source uses `invalid input syntax for integer: "%s"`; both are dynamic templates, not a universal localized string. Other fixed callers include COPY reject-limit reporting, enum input, and extension validation, so the primary text and context can differ.

## Diagnosis {#diagnosis}

Record the destination type, the exact value after client encoding and parameter binding, and whether the operation is a cast, assignment, text `COPY` field, enum input, or another type wrapper. Distinguish malformed text (`22P02`) from numeric range overflow (`22003`), invalid date/time syntax (`22007`), invalid binary representation (`22P03`), and a malformed COPY file/header or framing (`22P04`). Do not diagnose a binary COPY payload with the text-input message alone.

## Response {#response}

Validate at the input boundary and preserve the intended target type. Retry only after correcting the value; do not silently truncate or turn the value into NULL unless that is the explicit business rule. In an explicit transaction, an input ERROR leaves the transaction aborted (`25P02`); use `ROLLBACK` or a savepoint such as `ROLLBACK TO SAVEPOINT convert_input` before continuing. A `COPY` error likewise requires transaction recovery before another command.

## Observed diagnostics {#messages}

The fixed ordinary integer path has `ERROR` severity and the version-specific primary templates above. The selected runtime records the exact values: `"not-an-integer"` produced 22P02, and a valid `"42"` returned 42 on the same autocommit session.

## Representative case {#case}

The shared registry sends one invalid text cast in autocommit, inspects the real diagnostic and `IDLE` state, then sends a valid integer text on the same connection. That observed recovery is different from an explicit transaction, where the client must roll back or roll back to a savepoint before continuing. The page uses the registry SQL; the runner substitutes no hidden second definition.

<!-- BEGIN SQLSTATE SNIPPET: invalid_integer_text -->

```sql
SELECT 'not-an-integer'::integer;
SELECT '42'::integer
```

<!-- END SQLSTATE SNIPPET -->

The selected PostgreSQL 18.6 and 10.21 runs passed SQLSTATE, severity, state or disconnect recovery, repair, cleanup, and isolated-target stop assertions. See [`case JSON`](../data/cases/22p02.json) and [`authored evidence`](../data/evidence/22p02.json).

## Versions {#versions}

The locked catalogue records 22P02 from 7.4 through the listed snapshots. The bounded runtime comparison passed on 18.6 and 10.21, with the primary wording differing as shown; that does not generalize every 22P02 caller or every intermediate implementation.

## Related {#related}

- [`22003`](../22003/)
- [`22007`](../22007/)
- [`22P03`](../22p03/)
- [`22P04`](../22p04/)

## Sources {#sources}

- `src.errcodes.18.6` — `src/backend/utils/errcodes.txt` at `724edf9bde9d356724ad384a2e196edc3c9f80f7`; blob SHA-256 `6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba` ([source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt#L206)).
- `src.invalid-integer.18.6` — `src/backend/utils/adt/numutils.c` at `724edf9bde9d356724ad384a2e196edc3c9f80f7`; blob SHA-256 `9018d559d8a2b04f6d3fa8fedeb754fc5f1f8cd8594292e6adc5108e8f97f1bf` ([source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/numutils.c#L614-L618)).
- `src.invalid-integer.10.23` — `src/backend/utils/adt/numutils.c` at `02991e79f8f58bc208f05dcc8af0c62dbe0a6ea4`; blob SHA-256 `6cb3fd7e4b38a66c16f2cc4a3de0c52ce44e01dd22edd3dd9340d2a8faea0d35` ([source](https://github.com/postgres/postgres/blob/02991e79f8f58bc208f05dcc8af0c62dbe0a6ea4/src/backend/utils/adt/numutils.c#L59-L62)).
- `src.copy-text.18.6` — the fixed text-COPY conversion/reject-limit path in `src/backend/commands/copyfrom.c` at lines 1169-1172 ([source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/commands/copyfrom.c#L1169-L1172)).
- `src.calls.REL_18_6` / `src.calls.REL_10_23` — fixed call scans, SHA-256 `9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf` / `00d16d3eb01b71ccf1b245c8f3102f9d0ec9f36fb02777b8dd1b99fcb263040c`.
- `manifest.22P02` / `snippet-registry.22P02` — hashes are recorded in `evidence/22P02.json` and each selected runtime record.
