Restoring a Half‑Completed Borg Backup That Stopped at 50%

When a Borg backup stops halfway

You’re in the middle of a nightly backup of your homelab server, the progress bar hits 50 % and then the process dies. Maybe a sudden power loss, a network hiccup, or a disk error. The archive on the remote storage looks like a half‑filled container. You’re left with a repository that has a partially written archive. How do you recover the data you already captured, and how do you finish the backup without starting from scratch?

Below is a step‑by‑step guide that covers:

  • Detecting the incomplete archive
  • Validating the repository
  • Extracting the data that was already written
  • Resuming the backup
  • Cleaning up corrupted chunks
  • Security‑aware best practices

Everything is written with the assumption that you’re running a recent Linux distribution (2026‑era), using Borg 1.4.x, and that your repository is stored on an NFS share or an SSH‑based remote.


1. Find the incomplete archive

Borg keeps a list of all archives in the repository. The first thing is to see which archive is stuck.

# List archives with their size and status
borg list /mnt/backup_repo --format="{archive}\t{size}\t{time}\t{message}"

The --format option lets you see the archive name, the size on disk, the timestamp, and any message that Borg may have stored. An incomplete archive will usually have a size that is noticeably smaller than the others and will be marked with a * in the message column.

If you see something like:

2026-09-13T02:15:00Z  1.2G  2026-09-13T02:15:00Z  *

the asterisk indicates that Borg detected a problem during creation.


2. Verify the repository

Before you start pulling data out, make sure the repository itself is healthy. A corrupted repository can make the whole process impossible.

borg check /mnt/backup_repo --repair
  • --repair will attempt to fix any inconsistencies it finds.
  • If you don’t want to touch the data yet, run it without --repair first.

If borg check reports “All chunks are valid” you’re good to go. If it finds missing chunks, note the chunk IDs; you’ll need them later.


3. Inspect the archive with borg mount

Mounting the repository gives you a read‑only view of the archive’s contents. It’s a quick way to see what Borg thinks is there.

mkdir -p /tmp/borg_mount
borg mount /mnt/backup_repo::2026-09-13T02:15:00Z /tmp/borg_mount

Now look inside /tmp/borg_mount. If you see a partially populated directory tree, that confirms the archive is incomplete. Unmount when done:

borg umount /tmp/borg_mount

4. Extract what’s already there

If you need the data immediately, extract the part that Borg has already written. The --partial flag tells Borg to ignore missing chunks and pull out everything it can.

borg extract /mnt/backup_repo::2026-09-13T02:15:00Z --partial --destination /var/restore
  • --partial – extract even if the archive is incomplete.
  • --destination – choose where the files should land.

After extraction, verify the files:

diff -r /var/restore /home/user

If the diff shows only a few missing files, you’re ready to finish the backup.


5. Finish the backup

5.1. Resume with borg create --partial

Borg does not have a true “resume” command, but you can create a new archive that starts where the old one left off. The trick is to use the same source directory and the --partial flag again, but this time you’ll also use --exclude to skip files that were already backed up.

# Find files that were already backed up
borg list /mnt/backup_repo::2026-09-13T02:15:00Z --format="{path}\n" | sort > /tmp/old_files.txt

# Create a new archive that excludes those files
borg create \
  --progress \
  --stats \
  --compression lz4 \
  --exclude-from /tmp/old_files.txt \
  /mnt/backup_repo::2026-09-13T02:45:00Z \
  /home/user
  • --exclude-from reads a list of paths to skip.
  • The new archive will contain only the missing pieces.

After the new archive finishes, you can delete the old, incomplete one:

borg delete /mnt/backup_repo::2026-09-13T02:15:00Z

5.2. Use borg prune to keep the repository tidy

If you’re running a regular backup schedule, you probably have a prune policy. Run it after the new archive is complete to remove any orphaned chunks that the old archive left behind.

borg prune /mnt/backup_repo --keep-last 7 --keep-daily 30

6. Clean up corrupted chunks

If borg check reported missing or corrupted chunks, you have two options:

  1. Re‑create the archive – delete the incomplete archive and run a fresh backup.
  2. Repair the chunks – if you have a backup of the original data, you can re‑upload the missing chunks manually. This is rarely necessary unless you’re on a very tight storage budget.

The simplest approach is to delete the bad archive and let Borg rebuild it. Borg’s deduplication will reuse existing chunks, so you won’t lose any data.

borg delete /mnt/backup_repo::2026-09-13T02:15:00Z

7. Prevent future half‑completed backups

Issue Mitigation Trade‑off
Power loss UPS + systemd watchdog Extra hardware cost
Network hiccups borg create --progress --stats --compression lz4 + --remote-path Slightly larger archive size
Disk errors fsck before backup + --check after Extra maintenance time
Repository corruption Regular borg check --repair + borg prune Extra disk usage for checks

7.1. Use a watchdog

If you’re on a systemd‑based distribution, enable a watchdog that will restart the backup if it dies. A simple unit looks like this:

[Unit]
Description=Borg backup watchdog
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/borg create --remote-path=borg --stats /mnt/backup_repo::$(date -Iseconds) /home/user
Restart=on-failure
RestartSec=30
WatchdogSec=300

[Install]
WantedBy=multi-user.target

Enable and start it:

systemctl enable --now borg-watchdog

Now if the backup crashes, systemd will bring it back up automatically.


TAGS: borg backup incomplete repository recovery


See also