Recover PostgreSQL from corrupted WAL
Symptom
PostgreSQL cannot start and its deployment logs contain a checkpoint error such as:
FATAL: could not locate a valid checkpoint recordThe logs might also contain invalid primary checkpoint record or the same
checkpoint message at the PANIC level.
Cause
PostgreSQL uses its write-ahead log (WAL) to recover committed changes after a restart. A damaged WAL segment or control file can leave PostgreSQL without a valid checkpoint from which to start.
Solution
If point-in-time recovery is enabled, restore the database to a new service. Otherwise, restore a volume backup when one is available. Both options are safer than resetting the WAL because they don't modify the source database.
pg_resetwal can cause data loss and leave partially committed transactions in
the database. Use it only as a last resort when PostgreSQL cannot start and you
don't have a usable backup.
Create a volume backup
Preserve the current state before changing the database files:
- Open the PostgreSQL service in Railway.
- Select the Backups tab.
- Create a manual backup of the database volume.
Stop PostgreSQL
Prevent PostgreSQL from running while you reset the WAL:
- Open the PostgreSQL service Settings.
- Set the Custom Start Command to
sleep infinity. - Deploy the change.
The new deployment keeps the container running without starting PostgreSQL.
Connect to the container
In a terminal linked to the Railway project and PostgreSQL service, connect to the deployment:
railway sshConfirm that PGDATA points to the PostgreSQL data directory and that its major
version matches the pg_resetwal major version:
printf '%s\n' "$PGDATA"
cat "$PGDATA/PG_VERSION"
pg_resetwal --versionReset the WAL
Preview the values that pg_resetwal will use without changing any files:
su postgres -c "pg_resetwal --dry-run '$PGDATA'"Review the output, then force the reset:
su postgres -c "pg_resetwal --force '$PGDATA'"pg_resetwal must run as the postgres user while the server is stopped. The
command must come from the same PostgreSQL major version as the data directory.
Restart PostgreSQL
Return the service to its normal start command:
- Remove
sleep infinityfrom Custom Start Command. - Deploy the change.
- Check the deployment logs to confirm that PostgreSQL starts.
Rebuild the database
Treat the recovered database as inconsistent. Don't run data-modifying queries. Immediately create a logical dump, initialize a new PostgreSQL service, restore the dump into it, and check the restored data for inconsistencies.
For the required recovery steps and caveats, see the
PostgreSQL pg_resetwal documentation.