Troubleshooting

Start with the error message, check the local file or process it names, and then retry the smallest command that failed.

init says the instance directory is not empty

init refuses to use a folder that already contains files.

Use a new folder or move the existing files before trying again:

mv ./stage-data ./stage-data-old
stage-pg init ./stage-data --tls-cert /path/server.crt --tls-key /path/server.key

Do not delete the old folder unless you are sure it contains no database you need.

init says TLS certificate or key is missing

The certificate and private key must exist before PostgreSQL is initialized:

ls -l /etc/stage-pg/postgres.crt /etc/stage-pg/postgres.key

The private key must not be readable by group or other users:

chmod 600 /etc/stage-pg/postgres.key

stage-pg does not create certificates. Get them from the CA or certificate system you already use.

init or run cannot find PostgreSQL tools

Make sure all of these are installed and on the same major version:

initdb --version
pg_ctl --version
psql --version
pg_dump --version
pg_restore --version

If they are not on PATH, pass their directory during init:

stage-pg init ./stage-data \
  --tls-cert /path/server.crt \
  --tls-key /path/server.key \
  --postgres-bin-dir /usr/lib/postgresql/17/bin

PostgreSQL major version mismatch

The version in config.json must match the PostgreSQL tools that stage-pg finds. Check the configured value and the installed tools:

jq '.postgresMajor' ./stage-data/config.json
pg_dump --version

Use the matching binary directory or recreate the instance with the intended major version.

port ... is already in use

Each instance gets one stable port. Another process or another instance already owns the selected port.

Check the listener with your operating system tools, then stop the conflicting process or choose a different instance host. Do not edit the port while the instance is running or while Cloudflare/Tailscale still point at the old value.

cloudflared fails to start

Check the local token file and executable:

ls -l /etc/stage-pg/cloudflared-token
cloudflared --version

The token file must be a readable regular file with restrictive permissions. stage-pg does not test Cloudflare reachability before starting, so a local run failure and a remote Worker connection failure are different problems.

Tailscale administrators cannot connect

Check each part of the path:

  1. PostgreSQL is running with stage-pg run.

  2. Tailscale Serve uses the saved port on both sides:

    tailscale serve status
  3. The tailnet policy allows the administrator to reach that port.

  4. The client uses the Tailscale hostname, the saved port, the stage_admin role, and PostgreSQL TLS.

stage-pg does not create the Serve rule or tailnet policy for you.

Backup fails

Check the PostgreSQL tools and the local backup directory:

pg_dump --version
ls -ld ./stage-data/backups

An incomplete .part file can be removed after the failed command. A published .dump file should be kept unless its manifest or checksum is invalid.

S3 upload fails but a local dump exists

This is expected behavior for an upload-only failure. Check the AWS-style environment variables and bucket settings:

test -n "$AWS_ACCESS_KEY_ID" && echo access key is set
test -n "$AWS_SECRET_ACCESS_KEY" && echo secret key is set

The local dump remains the usable backup. Fix the credentials or endpoint and run stage-pg backup again.

Restore reports a checksum or manifest error

Do not restore an artifact that fails verification. Copy a fresh dump from the original backup location or S3, then retry:

stage-pg restore ./stage-data ./stage-data/backups/20260807T180000Z.dump

Restore always targets a new database. It does not overwrite the live staging database when validation fails.