Docket

TROUBLESHOOTING

pg_restore says unsupported version in file header

The number in that message is the archive format, not a Postgres version, and it tells you exactly which client wrote the file.

7 MIN READ Last updated 23 August 2026

pg_restore: error: unsupported version (1.14) in file header means the dump file was written by a newer pg_dump than the pg_restore you are running. The number is the archive format version, not a PostgreSQL version. Restore the file with a pg_restore at least as new as the client that produced it, and it loads.

The mapping below was read from PostgreSQL's own source tree on 23 August 2026, one release branch at a time, rather than from a summary.

What does the number in the message actually mean?

A custom-format dump is not SQL. It is an archive with a header, and the header starts with the five bytes PGDMP followed by three single bytes: the major, minor and revision of the archive format. That format has its own version number that moves independently of the database, and pg_dump bumps it when the archive layout changes. pg_restore reads those three bytes first, compares them against the highest format its own code understands, and stops before touching anything if the file is from the future.

You can read the header yourself without any Postgres installed at all:

head -c 5 board.dump
xxd -l 8 board.dump

The first prints PGDMP. The second prints something like 5047 444d 5001 0e00, where 01 0e is 1 and 14, so the file is archive format 1.14. That maps to a client version:

Archive format in the headerWritten by pg_dump version
1.1311 and earlier
1.1412, 13, 14 and 15
1.1516
1.1617 and 18

So unsupported version (1.14) is a PostgreSQL 12 to 15 dump being fed to a pg_restore from 11 or older, which is the situation in the Stack Overflow question that carries this exact title, at 216,341 views. The (1.13) variant, at 120,644 views on its own question, is the same trap one release earlier.

Why does it refuse instead of trying its best?

Because a partial restore of a customer-facing database is worse than a failed one. PostgreSQL applies the same rule on the dump side, and states it plainly in the manual:

pg_dump cannot dump from PostgreSQL servers newer than its own major version; it will refuse to even try, rather than risk making an invalid dump.

PostgreSQL 18 documentation, pg_dump

The direction that is safe is always the same one: the client may be newer than the thing it is reading, never older. The full set, from the pg_dump and pg_restore manual pages:

What you are doingAllowed
Dumping with a pg_dump older than the serverNo, it aborts
Dumping with a pg_dump matching or newer than the serverYes, back to server version 9.2
Restoring a dump with an older pg_restoreNo, this error
Restoring a dump with a matching or newer pg_restoreYes
Loading a dump into an older major serverNot guaranteed, and may need hand editing

How do you restore the file you already have?

The reliable move is to stop using whatever client is on your laptop and run the restore from inside the container that runs the database, where the versions cannot disagree.

1. Read the header and work out what wrote it, using the table above.

2. Copy the dump into the database container.

docker compose cp board.dump db:/tmp/board.dump

3. Restore from inside it, using its own binaries.

docker compose exec db pg_restore -U postgres -d board \
  --clean --if-exists --no-owner /tmp/board.dump

4. If the server itself is older than the dump, no client will save you. Two honest options: bring the target server up to at least the major version that wrote the file, or, if the source database is still running, take a fresh dump from it in plain SQL with -Fp, which psql will load without any archive version check at all.

The one-off way to get a newer client without installing anything is a throwaway container, which is worth knowing when the target is a managed database rather than one of your own:

docker run --rm -i -v "$PWD:/b" postgres:18 \
  pg_restore -h db.example.com -U postgres -d board /b/board.dump

How do you tell it worked?

Read the archive's table of contents before you commit to anything. If this command prints a list, the file is intact and the client can read it, which separates a version problem from a corrupt download:

docker compose exec db pg_restore --list /tmp/board.dump | head

After the restore, count rows rather than trusting the exit code, then open the board and look at a post with comments and votes on it. A restore that reports success and quietly loses a table's contents is unusual, but the only proof is the surface your customers see. Backing up a request board covers the drill in full, including the part everybody skips, which is restoring into a scratch database on a normal Tuesday rather than during an incident.

How do you stop it happening again?

Take the dump with the server's own binaries, every time, and never with whichever pg_dump your package manager last updated:

docker compose exec -T db pg_dump -U postgres -Fc board \
  > "board-$(date +%F).dump"

Record the server version next to the file, so a restore in eighteen months does not begin with archaeology:

docker compose exec -T db psql -U postgres -tAc \
  "show server_version" > board-version.txt

And consider whether you need the custom format at all. Plain SQL, -Fp, is a text file that psql loads with no version handshake in the way. You give up parallel restore, selective restore of single tables, and compression, which matter on a large database and matter very little on a request board with a few thousand rows.

Your own support centre, in your own repository

One payment, no subscription, unlimited products.

What if the message is slightly different?

What you seeWhat it usually is
unsupported version (1.16) in file headerA PostgreSQL 17 or 18 dump being read by a client from 16 or older
pg_dump: error: aborting because of server version mismatchThe other direction. Your client is older than the server, as in this docker-library discussion where pgAdmin used its own bundled binaries
input file does not appear to be a valid archiveNot a custom-format archive at all. Usually a plain SQL dump, which needs psql, or a file that is still compressed
pg_restore: error: could not open input fileA path problem, commonly a file left on the host while the command runs inside the container
The restore runs but every object is owned by the wrong roleNot a version problem. Add --no-owner, and create the roles first

The pgAdmin case surprises people. It ships its own copies of pg_dump and pg_restore, often a different major version from the server you just connected it to. If the graphical tool fails where the command line inside the container works, that is the difference.

Does a support centre need a database dump at all?

Only if it has a database. Docket keeps its content as files in your own git repository, so the thing you would restore is a clone, and a git clone has no archive format to disagree about. That is a different set of problems rather than fewer of them: a repository that exists in exactly one place is not a backup either, and encrypted submitter emails still need a key you have not lost. Anyone running Fider, LogChimp or another Postgres-backed board is solving a harder problem, and this page exists because its tooling fails in a way that is easy to fix and hard to diagnose.

Frequently asked questions

Is 1.14 a PostgreSQL version?

No. It is the version of the custom archive format, written into the first eight bytes of the dump file. Archive format 1.14 was produced by pg_dump from PostgreSQL 12 through 15, 1.15 by 16, and 1.16 by 17 and 18. Reading the header tells you which client made the file without needing to remember when it was taken.

Can I edit the file header to make it load?

No, and it would not help if you could. The format number describes how the rest of the archive is laid out, so an older pg_restore told to ignore it would misread the table of contents. Use a newer client instead, or regenerate the dump in plain SQL from the source server.

Why did the same command work last month?

Almost always because a client got upgraded underneath you: a package manager updated the Postgres client tools on the machine taking the dump, a CI image floated to a newer tag, or the database container itself moved a major version. Running the dump inside the database container removes the moving part.

Can I restore a newer dump into an older server?

Not reliably. The PostgreSQL manual is explicit that a dump's output is not guaranteed to load into a server of an older major version, even if the data originally came from one, and it may need hand editing to strip syntax the older server does not understand. Upgrade the target instead where you can.

Does the plain SQL format avoid all of this?

It avoids the archive version check, because there is no archive: psql simply executes the statements. It does not avoid SQL that an older server cannot parse, so a dump from a much newer database can still fail on the way in. For a small board, plain SQL is usually the easier format to live with.