# 22013 — invalid_preceding_or_following_size

> Source-backed reference for PostgreSQL SQLSTATE 22013.
---

## At a glance {#at-a-glance}
A window-frame offset is negative in a fixed `ROWS` or `GROUPS` executor path. PostgreSQL 18.6 reports either `frame starting offset must not be negative` or `frame ending offset must not be negative` with SQLSTATE `22013`.

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

| Field | Value |
| --- | --- |
| SQLSTATE | `22013` |
| Condition | `invalid_preceding_or_following_size` |
| Status | `active` |
| Known present by | `11.0` |
| Locked snapshots | `11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3` |
| Macros | `ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE` |
| Aliases | `—` |

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

## Meaning {#meaning}
`calculate_frame_offsets` evaluates the start and end expressions once for a window scan. After a non-NULL value is copied, the `ROWS` and `GROUPS` branches interpret it as an `int8` offset and reject a negative value with `22013`. The NULL guards use `22004` and different primary messages. `RANGE` frames use type-specific `in_range` helpers: the integer helper rejects a negative offset, numeric rejects NaN, negative infinity, or a negative value, the float helper rejects NaN or a negative value, and the timestamp-with-interval helper rejects a negative interval. These helpers use the same `22013` primary, so the frame mode and resolved offset type are part of the diagnosis.

## Diagnosis {#diagnosis}
Read the frame mode, endpoint named by the primary, and the evaluated offset expression. A negative start or end in `ROWS`/`GROUPS` is this condition. In `RANGE`, inspect the resolved offset type: a negative integer or interval, or the rejected NaN/negative numeric and float values, reaches the same code. A NULL start or end is `22004`, not `22013`. This is a frame-boundary validation failure, not a generic arithmetic overflow.

## Response {#response}
For a `ROWS` or `GROUPS` endpoint, provide a non-negative `int8`-compatible offset; for `RANGE`, provide a value accepted by the resolved type-specific `in_range` helper. Provide a non-NULL value when NULL was the actual issue. Because the cited guard raises `ERROR`, roll back or roll back to an existing savepoint in an explicit transaction before retrying; autocommit can retry only the corrected statement.

## Messages {#messages}
- Primary, `ERROR`: `frame starting offset must not be negative`.
- Primary, `ERROR`: `frame ending offset must not be negative`.
- Primary, `ERROR`: `invalid preceding or following size in window function` for the cited type-specific `RANGE` offset guards.
- The cited guards add no DETAIL or HINT. NULL endpoints use SQLSTATE `22004` with `frame starting offset must not be null` or `frame ending offset must not be null`.

## Versions {#versions}
The locked catalogue records this condition from 11.0; fixed source coverage is PostgreSQL 18.6. The cited executor guard covers `ROWS`/`GROUPS`; the cited type-specific `in_range` helpers cover representative `RANGE` offsets.

## Related {#related}
[`22004`](../22004/), [`22012`](../22012/), [`22003`](../22003/)

## Sources {#sources}
- [`src/backend/executor/nodeWindowAgg.c#L2144-L2210`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/executor/nodeWindowAgg.c#L2144-L2210) contains the start/end expression evaluation, NULL `22004` guards, and negative `ROWS`/`GROUPS` offset `22013` guards.
- Representative `RANGE` helpers use the same primary: [`int8.c#L400-L420`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/int8.c#L400-L420) rejects negative integer offsets; [`numeric.c#L2690-L2715`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/numeric.c#L2690-L2715) rejects NaN, negative infinity, and negative numeric offsets; [`float.c#L1105-L1125`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/float.c#L1105-L1125) rejects NaN or negative float offsets; and [`timestamp.c#L3860-L3885`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/adt/timestamp.c#L3860-L3885) rejects negative interval offsets.

Runtime verification is `not_run`; this source evidence is not a runtime observation. The structured [evidence record](../data/evidence/22013.json) retains the two endpoint variants, the generic `RANGE` primary, and their scope.
