2202E — array_subscript_error
At a glance
2202E is PostgreSQL’s array_subscript_error condition in Class 22, Data Exception. The directory keeps ERRCODE_ARRAY_ELEMENT_ERROR as a compatibility alias and uses ERRCODE_ARRAY_SUBSCRIPT_ERROR for the named condition. Both macros encode the same SQLSTATE.
Do not treat every out-of-range-looking expression as an error. PostgreSQL documents that an array subscript read outside the current bounds returns NULL; a read with the wrong number of subscripts also returns NULL. Array slices have their own historical rules: a slice wholly outside the bounds can produce an empty zero-dimensional array, while a partially overlapping slice is reduced to the overlap.
2202E is raised when another path validates a shape or subscript and rejects it. In the core source this includes incompatible dimensions during array concatenation or construction, invalid slice boundaries, and some subscripted assignment checks. The operation matters as much as the index value.
The executable representative case is incompatible_array_dimensions. It passed on PostgreSQL 18.6 and 10.21. The case raises 2202E for an incompatible concatenation, then proves that the same autocommit connection is IDLE and can execute a valid follow-up concatenation. The SQL excerpt below is the complete ordered pair from the shared snippet registry; the runner remains the single owner of setup and cleanup.
| Field | Value |
|---|---|
| SQLSTATE | 2202E |
| Condition | array_subscript_error |
| 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_ARRAY_ELEMENT_ERROR, ERRCODE_ARRAY_SUBSCRIPT_ERROR |
| Aliases | ERRCODE_ARRAY_ELEMENT_ERROR |
Meaning and trigger paths
The 18.6 directory row is 2202E E ERRCODE_ARRAY_SUBSCRIPT_ERROR array_subscript_error. The preceding alias row is 2202E E ERRCODE_ARRAY_ELEMENT_ERROR; the source comment explains that SQL99’s “array element error” is the subscript error. Code that still names the alias is therefore referring to this same SQLSTATE, not to a second condition.
An array has a rank, a length for each dimension, and lower bounds. PostgreSQL does not require every array to start at one, so diagnostics should inspect the actual bounds rather than assume them. The documented array_ndims, array_dims, array_lower, array_upper, and cardinality functions expose the metadata needed to do that. Use them in the same session when an error needs to be diagnosed; they are inspection tools, not evidence that a particular error was triggered.
The main core paths are:
- Array element or slice assignment.
arrayfuncs.cvalidates subscripts and slice boundaries. One-dimensional arrays can be enlarged by assigning to a new element, with intervening positions filled byNULL; multidimensional enlargement is not supported. A slice assigned to an empty array must provide both boundaries. These rules mean that an assignment outside the current read bounds must be analyzed as an assignment operation, not inferred fromSELECT a[n]. - Array concatenation.
array_catraises2202Ewhen equal-rank arrays have different lengths or lower bounds on a non-concatenated dimension. This is the path exercised by the representative case. - Multidimensional construction. The expression evaluator raises the same condition when non-empty array expressions used to form a multidimensional array have incompatible dimensions.
The source tree contains other callers, including data-type helper paths. Class 22 is the broad data-exception class; the 2202E row and its source function identify when this particular shape or subscript contract failed.
Messages and diagnostics
The canonical executable excerpt is:
The first statement has two two-dimensional arrays whose inner dimensions differ. PostgreSQL 18.6 reports:
The same case on PostgreSQL 10.21 reports the same primary and detail text, with the historical array_userfuncs.c source line 356. The second statement returns {1,2,3,4}. The message and detail are templates from the concatenation path, not a universal wording for every 2202E.
Other source-confirmed templates include array subscript out of range, array slice subscript must provide both boundaries with a detail explaining empty-array assignment, and upper bound cannot be less than lower bound. Preserve message_detail, message_hint, source_file, source_function, and source_line when the driver exposes them; they often distinguish a slice check from a concatenation check.
Diagnosis
Start by classifying the expression:
- A plain element read such as
a[999]can legitimately produceNULL. Checka IS NULL, the subscript expressions, and the stored bounds before calling it a server error. - A slice read can return
NULL, an empty zero-dimensional array, or a reduced overlap according to the documented slice rules. Do not map those values to2202Ewithout an error response. - Assignment, array construction, and concatenation execute validation code. Record the array rank, dimensions, lower bounds, number of supplied subscripts, and whether the statement is changing the value.
For a real error, record SQLSTATE, severity, primary message, detail, hint, statement position, and the relation or function context. Compare the failing expression with array_ndims, array_dims, array_lower, and array_upper from the same value or source expression. For concatenation, compare every non-concatenated dimension and lower bound. For a slice, verify both boundaries and their order. For construction, inspect every subarray’s shape.
In PL/pgSQL, a handler can catch array_subscript_error or SQLSTATE '2202E', but the handler’s transaction behavior depends on the block. A block with an EXCEPTION clause runs its protected body in a subtransaction; if the body errors, persistent changes made there are rolled back before the handler runs. A broad OTHERS handler also has documented exclusions, so use a specific condition when the application intends to repair an array operation.
Response
Repair the operation that violated the shape contract. Normalize dimensions and lower bounds before concatenating; provide complete, ordered slice boundaries; use a one-dimensional expansion only when its NULL fill behavior is intended; or rebuild multidimensional values with matching subarrays. If NULL is a valid result of a read, handle it as a value and do not “fix” it with COALESCE before deciding whether the application should distinguish an absent element from a stored NULL element.
The representative error ran in autocommit. After the failed statement the connection was IDLE, and the valid concatenation succeeded. In an explicit transaction, an ERROR normally aborts the transaction until ROLLBACK or a rollback to a savepoint; the connection itself need not be closed. A PL/pgSQL block with an exception clause can contain the failure in its protected subtransaction body, rolling back that body’s changes before its handler runs. Verify the actual client transaction status rather than deriving connection fate from 2202E alone.
Versions
The catalogue records 2202E in the locked 7.4–8.4.22 pre-9.0 formal sources, every formal snapshot from 9.0.23 through 18.6, and the 19 Beta 3 preview. The same-tag REL8_1_4 errcodes.sgml table already lists 2202E as array_subscript_error, confirming that condition-name observation by 8.1.4. Candidate source gaps remain for 7.0–7.3, so the 7.4 observation is a presence boundary rather than an exact introduction version. The fixed 18.6 source commit is 724edf9bde9d356724ad384a2e196edc3c9f80f7; the alias and named macro are both present in its errcodes.txt row.
The incompatible-dimension case passed on PostgreSQL 18.6 and 10.21 with the same primary/detail wording and different source line numbers. That cross-version result does not guarantee unchanged wording for every older minor release or every other 2202E call path.
Related
22000 — data_exception is the broad Class 22 category. 22005 — error_in_assignment is a distinct assignment condition and should not be substituted for an array-specific 2202E path. 22P02 — invalid_text_representation concerns input text parsing. 2202E also differs from a successful out-of-bounds read, which returns NULL under the documented array rules.
Sources
The structured evidence is recorded in the public evidence JSON. Source records are pinned to PostgreSQL commit 724edf9bde9d356724ad384a2e196edc3c9f80f7; runtime records retain the shared snippet registry, both target versions, and run 2202E-snippet-registry-final-20260909.
src.errcodes.18.6—errcodes.txtsrc.array-userfuncs.18.6—array_userfuncs.csrc.arrayfuncs.18.6—arrayfuncs.csrc.exec-expr.18.6—execExprInterp.cdoc.array.18anddoc.func.18— Arrays and Array Functions and Operatorsdoc.transactions.18— Transactions