found xmin N from before relfrozenxid N

SQLSTATE XX001 condition data_corrupted class XX — Internal Error severity ERROR
Reproduced & verified on PostgreSQL 14.23, 15.18, 16.14, 17.10 and 18.4 — identical message on every version.
Last reviewed 11 Jun 2026 · Reproduced live with the SQL on this page.

Symptoms

VACUUM or a scan found a tuple whose xmin predates the relation’s frozen-xid horizon — an impossible state that indicates corruption. PostgreSQL raises SQLSTATE XX001 (data_corrupted).

What the server log shows

ERROR:  found xmin 1234 from before relfrozenxid 5678
CONTEXT:  while scanning block 42 of relation "public.orders"

Why PostgreSQL raises this — what the manual says

As Section 24.1.5 Preventing Transaction ID Wraparound Failures explains:

relfrozenxid records the oldest unfrozen XID still present in a relation; finding a live tuple whose xmin predates that horizon should never happen, so PostgreSQL treats it as corruption of transaction-ID metadata rather than a recoverable vacuum state.

Freezing guarantees that no live tuple has an xmin older than relfrozenxid. Finding one violates that invariant — the visibility bookkeeping is corrupt — so PostgreSQL reports XX001.

Common causes

How to fix it

  1. Treat as corruption: investigate hardware/storage immediately.
  2. Restore the affected table/database from a known-good backup.
  3. Use amcheck/pg_amcheck to assess the extent of damage.

Related & next steps

Reference: PostgreSQL 18 Section 25.1 “Routine Vacuuming”.