# 72000 — snapshot_too_old

> Source-backed historical reference for PostgreSQL SQLSTATE 72000.
---

# 72000

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

`72000` is a historical `snapshot_too_old` error. PostgreSQL 16.15 still defines and emits it; the SQLSTATE was removed in the PostgreSQL 17 major line. PostgreSQL 16.15 is therefore a later minor snapshot of the last major line, not the removal point.

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

| Field | Value |
| --- | --- |
| SQLSTATE | `72000` |
| Condition | `snapshot_too_old` |
| Status | `removed` |
| Known present by | `9.6.0` |
| Locked snapshots | `9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15` |
| Macros | `ERRCODE_SNAPSHOT_TOO_OLD` |
| Aliases | `—` |

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

## Meaning {#meaning}

In the fixed 16.15 sources, `old_snapshot_threshold` is a `PGC_POSTMASTER` integer GUC; `-1` disables the feature. The inline `TestForOldSnapshot` guard requires a non-negative threshold, an MVCC or TOAST snapshot with a valid LSN, and a page LSN newer than the snapshot. It then calls `TestForOldSnapshot_impl`, which additionally requires a permanent, non-catalog relation that allows early pruning and compares `snapshot.whenTaken` with `GetOldSnapshotThresholdTimestamp()`. If the snapshot is too old, the function raises **ERROR** `72000` with `snapshot too old`.

The threshold timestamp is maintained by the old-snapshot time-to-XID mapping used by early pruning and vacuum. The PG16.15 documentation says that dead data older than the threshold may be vacuumed, and a read of a page modified after the snapshot can fail; a materialized cursor or a system catalog may avoid the error. Space retained for detection is not released to the operating system until an explicit operation such as `VACUUM FULL`.

## Messages {#messages}

- **ERROR**, SQLSTATE `72000`: `snapshot too old`.

There is no current PG17/18 definition row in the locked catalogue. Do not infer a replacement SQLSTATE or claim that an unrelated current error is equivalent.

## Diagnosis {#diagnosis}

On PostgreSQL 9.6 through 16, record the major version, `SHOW old_snapshot_threshold`, transaction snapshot age, relation kind, page/read path, and vacuum or pruning history. Check whether the relation is excluded by the guard (for example a system catalog), whether the read used a materialized cursor or result set, and whether the setting was active at server start. A source-only review cannot establish the threshold or cleanup history on a live cluster.

## Response {#response}

This is a statement `ERROR`; in an explicit transaction, roll back the transaction or to an already-established savepoint before issuing more SQL. The old snapshot cannot be repaired in place: end or shorten the long-running reader, use a suitable startup configuration for the historical major (the GUC is `PGC_POSTMASTER`, so changing it requires restart), and rerun the whole read unit with an idempotent boundary. On PostgreSQL 17 and later, first identify the current error and mechanism instead of installing a `72000` handler based on the historical name.

## Versions {#versions}

The locked definition artifact records `72000` from 9.6.0 through 16.15 and no PG17/18 definition. The 16.15 source documents the GUC and guard; the fixed buffer-manager emitter is from commit `7d3e000c5961a544302072058a1184e9a588837b`. The catalogue boundary establishes removal in the PG17 major line, not in minor release 16.15.

## Related {#related}

[`40001`](../40001/), [`XX001`](../xx001/)

## Sources {#sources}

[`src/backend/storage/buffer/bufmgr.c#L5663-L5675`](https://github.com/postgres/postgres/blob/7d3e000c5961a544302072058a1184e9a588837b/src/backend/storage/buffer/bufmgr.c#L5663)

[`src/include/storage/bufmgr.h#L363-L392`](https://github.com/postgres/postgres/blob/7d3e000c5961a544302072058a1184e9a588837b/src/include/storage/bufmgr.h#L363)

[`src/backend/utils/time/snapmgr.c#L1697-L1714`](https://github.com/postgres/postgres/blob/7d3e000c5961a544302072058a1184e9a588837b/src/backend/utils/time/snapmgr.c#L1697)

[`src/backend/utils/misc/guc_tables.c#L3295-L3302`](https://github.com/postgres/postgres/blob/7d3e000c5961a544302072058a1184e9a588837b/src/backend/utils/misc/guc_tables.c#L3295)

[`doc/src/sgml/config.sgml#L2827-L2884`](https://github.com/postgres/postgres/blob/7d3e000c5961a544302072058a1184e9a588837b/doc/src/sgml/config.sgml#L2827)

The structured [evidence record](../data/evidence/72000.json) records the historical definition, guard, GUC, documentation, and source/runtime boundary.
