Skip to content

2202E — array_subscript_error

PostgreSQL uses SQLSTATE 2202E for array subscript and shape errors. Separate an out-of-bounds read that returns NULL from assignment, slice, constructor, and concatenation paths that validate array dimensions.

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:

  1. Array element or slice assignment. arrayfuncs.c validates subscripts and slice boundaries. One-dimensional arrays can be enlarged by assigning to a new element, with intervening positions filled by NULL; 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 from SELECT a[n].
  2. Array concatenation. array_cat raises 2202E when equal-rank arrays have different lengths or lower bounds on a non-concatenated dimension. This is the path exercised by the representative case.
  3. 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:

SELECT ARRAY[[1,2]] || ARRAY[[3]];
SELECT ARRAY[1,2] || ARRAY[3,4];

The first statement has two two-dimensional arrays whose inner dimensions differ. PostgreSQL 18.6 reports:

SQLSTATE: 2202E
severity: ERROR
message_primary: cannot concatenate incompatible arrays
message_detail: Arrays with differing element dimensions are not compatible for concatenation.
source: array_userfuncs.c / array_cat / line 450

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 produce NULL. Check a 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 to 2202E without 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.

22000data_exception is the broad Class 22 category. 22005error_in_assignment is a distinct assignment condition and should not be substituted for an array-specific 2202E path. 22P02invalid_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.