SQLSTATE XX001 ERROR Class XX: Internal Error

data_corrupted found xmin N from before relfrozenxid N — XX001

PostgreSQL error “found xmin N from before relfrozenxid N — XX001” (SQLSTATE XX001): what it means, common causes, and how to fix it.

PG 9.6, 10, 11, 12, 13, 14, 15, 16, 17, 18 Official docs
Last reviewed Jun 2026 Grounded in source

Diagnostic Queries

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).

  • A tuple’s xmin is older than relfrozenxid.
  • Often surfaced by VACUUM or amcheck.
  • Strong signal of heap corruption.

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

  • Storage/hardware faults corrupting tuple headers.
  • Bugs or unsafe recovery damaging visibility data.
  • A bad restore or filesystem-level tampering.

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”.

Was this helpful?