select open change scope Open full search

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

SQLSTATE / CLASS 22 · DATA EXCEPTION

array_subscript_error

SQLSTATE
2202E
Condition name
array_subscript_error
Class
Data Exception
Source macro
ERRCODE_ARRAY_SUBSCRIPT_ERROR
Evidence
Observed at runtime in the source evidence
Analysis & operational context

English SQLSTATE atlas: authored explanations and source/runtime evidence are separate from the manual definitions. View source ↗

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.

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.

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.

Source evidence

Evidence belongs to the frozen source and runtime versions listed here. It is not a runtime verification of the selected manual version.

2202E is the array_subscript_error condition in Class 22, Data Exception.

Method: Read the Class 22 section and the named 2202E row in the frozen errcodes.txt snapshot.

Limits: The directory identifies the condition but does not imply that every array read outside bounds raises it.

src.errcodes.18.6

ERRCODE_ARRAY_ELEMENT_ERROR is retained as an alias for the same 2202E SQLSTATE; ERRCODE_ARRAY_SUBSCRIPT_ERROR carries the array_subscript_error condition name.

Method: Read the adjacent alias and named macro rows and the SQL99 explanatory comment.

Limits: The alias is a source-level name; the wire value remains the five-character SQLSTATE.

src.errcodes.18.6

An array element read outside the current bounds, or a read with the wrong number of subscripts, returns NULL rather than raising an error.

Method: Read the official array subscript expression rules and examples.

Limits: This claim applies to reads; assignment, slice validation, construction, and concatenation have separate rules.

doc.array.18

A slice completely outside the current bounds can yield an empty zero-dimensional array, while a partially overlapping slice is reduced to the overlap.

Method: Read the documented slice behavior immediately following the element subscript rules.

Limits: The result also depends on NULL array or subscript expressions; it is not evidence of a 2202E error.

doc.array.18

One-dimensional subscript assignment can enlarge an array and fill intervening positions with NULL; multidimensional enlargement is not supported, and empty-array slice assignment requires both boundaries.

Method: Read the official assignment rules and the fixed arrayfuncs validation branches.

Limits: Whether a particular assignment raises 2202E depends on the array value, dimensions, and exact operation.

doc.array.18 src.arrayfuncs.18.6

array_cat raises 2202E when equal-rank arrays have differing non-concatenated dimensions or lower bounds.

Method: Trace the dimension and lower-bound comparison into the errcode and primary/detail construction in array_cat().

Limits: The primary and detail templates are specific to this concatenation path.

src.array-userfuncs.18.6

The expression evaluator raises 2202E when non-empty array expressions used to form a multidimensional array have incompatible dimensions.

Method: Read the multidimensional array constructor check and its ERRCODE_ARRAY_SUBSCRIPT_ERROR ereport.

Limits: This source path is separate from array_cat and has a different message template.

src.exec-expr.18.6

array_ndims, array_dims, array_lower, array_upper, and cardinality expose the rank, dimensions, bounds, and item count needed to inspect an array operation.

Method: Read the PostgreSQL 18 array function table entries.

Limits: Inspection functions describe the value supplied to them; they do not predict every coercion or operator resolution step.

doc.func.18

The incompatible_array_dimensions case returned 2202E with the incompatible concatenation diagnostic and then successfully executed a valid concatenation on the same connection.

Method: Read the stable case and ordered snippet registry, then compare the case_result diagnostics and status in both final target summaries and raw records.

Limits: The run is an autocommit concatenation case; it does not test every assignment, slice, constructor, or explicit-transaction path.

case-manifest.2202E snippet-registry.2202E.final runtime.2202E-snippet-registry-final-20260909.latest runtime.2202E-snippet-registry-final-20260909.pg10

The representative 2202E ERROR left the autocommit connection IDLE and the follow-up valid statement succeeded; explicit transaction and PL/pgSQL handler outcomes must be handled at their own boundaries.

Method: Read the transaction contract and the status/valid-array observations in both runner summaries.

Limits: No explicit transaction or PL/pgSQL exception handler was executed in this 2202E case.

doc.transactions.18 runtime.2202E-snippet-registry-final-20260909.latest runtime.2202E-snippet-registry-final-20260909.pg10

The locked catalogue records 2202E in the 7.4–8.4.22 pre-9.0 formal sources, every listed formal snapshot from 9.0.23 through 18.6, and 19beta3. The same-tag REL8_1_4 errcodes.sgml row 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 7.4 is a presence boundary rather than an exact introduction version.

Method: Read the manifest snapshot and the same-tag REL8_1_4 errcodes.sgml row for the code; the generated data record is a derived view.

Limits: The pre-9.0 source set is locked through 8.4.22 but candidate source gaps remain for 7.0–7.3; observed presence is not an asserted introduction version.

manifest.2202E doc.errcodes.8.1.4

Message templates

explicit ERROR with ERRCODE_ARRAY_SUBSCRIPT_ERROR · message.concat

Primary

cannot concatenate incompatible arrays

Detail

Arrays with differing element dimensions are not compatible for concatenation.

The template belongs to array_cat; runtime source lines are 450 on 18.6 and 356 on 10.21.

explicit ERROR with ERRCODE_ARRAY_SUBSCRIPT_ERROR · message.subscript

Primary

array subscript out of range

This template is emitted by validated assignment/slice paths; a plain out-of-bounds read is documented to return NULL.

explicit ERROR with ERRCODE_ARRAY_SUBSCRIPT_ERROR · message.slice-boundaries

Primary

array slice subscript must provide both boundaries

Detail

When assigning to a slice of an empty array value, slice boundaries must be fully specified.

This is the empty-array slice assignment path and is not a general read diagnostic.

explicit ERROR with ERRCODE_ARRAY_SUBSCRIPT_ERROR · message.bound-order

Primary

upper bound cannot be less than lower bound

This template is emitted by the slice boundary validation branch.

Reproduction & repair cases

incompatible_array_dimensions · PG 10, 18

Preconditions

  • A dedicated autocommit connection

Trigger: Concatenate two arrays whose element dimensions are incompatible.

Expected assertions

  • SQLSTATE is 2202E
  • The diagnostic explains the incompatible dimensions
  • A valid array operation succeeds afterward

Repair: Validate rank, bounds, and element dimensions before concatenation or assignment.

Cleanup: Drop the case schema with an owner connection.

Recorded runtime evidence

18.6 (Homebrew) · passed

Run: 2202E-snippet-registry-final-20260909

{
  "severity": "ERROR",
  "sqlstate": "2202E",
  "source_file": "array_userfuncs.c",
  "source_line": "450",
  "valid_array": [
    1,
    2,
    3,
    4
  ],
  "message_detail": "Arrays with differing element dimensions are not compatible for concatenation.",
  "message_primary": "cannot concatenate incompatible arrays",
  "source_function": "array_cat",
  "status_after_error": "IDLE"
}
10.21 (Debian 10.21-1.pgdg90+1) · passed

Run: 2202E-snippet-registry-final-20260909

{
  "severity": "ERROR",
  "sqlstate": "2202E",
  "source_file": "array_userfuncs.c",
  "source_line": "356",
  "valid_array": [
    1,
    2,
    3,
    4
  ],
  "message_detail": "Arrays with differing element dimensions are not compatible for concatenation.",
  "message_primary": "cannot concatenate incompatible arrays",
  "source_function": "array_cat",
  "status_after_error": "IDLE"
}

Definition snapshot: english-manuals:7ffb34c03fbefe1cb7faf043366… · English manual source