BTRFS-BACKUP-NG-VERIFY(1)

πŸ“¦
version 0.9.20 Β· 2 versions
, in fedora 43, fedora 44

πŸ’– btrfs-backup-ng-verify(1) πŸ’–

okay so bestie, welcome to the manual page for btrfs-backup-ng-verify β€” that's the verify command from the btrfs-backup-ng suite, living in the User Commands section of the manual (yes, section 1, the cool one). pull up a chair, this one is long and it's lowkey important πŸ’…


✨ NAME ✨

btrfs-backup-ng-verify β€” verify backup integrity 🫢

Like, does your backup actually work? That's the whole job.


πŸ¦‹ SYNOPSIS πŸ¦‹

btrfs-backup-ng verify [OPTIONS] LOCATION

🌸 DESCRIPTION 🌸

So the tea is this: btrfs-backup-ng verify checks that the backups sitting at a given LOCATION are valid and restorable. Not just "the folder has a name that looks right" β€” actually restorable. it gives you multiple levels of verification, going from a quick metadata glance all the way up to a full-blown restore test.

Verification works with btrfs backup subvolumes (both local directories and remote SSH locations), and also with raw targets (raw:// and raw+ssh://), which store btrfs send streams as plain files.

For a raw target, verification recomputes each stream's sha256 and compares it to the checksum sealed in the stream's .meta sidecar. That's literally the same integrity check performed by btrfs-backup-ng raw verify and before every raw restore. iconic consistency, no cap. 😌


πŸŽ€ ARGUMENTS πŸŽ€

  • LOCATION β€” the backup location you want verified. It can be a local path (like /mnt/backup/home), an SSH URL (like ssh://user@host:/path/to/backup), or a raw target (like raw:///mnt/usb/backups or raw+ssh://user@host:/backups). Pick your fighter. πŸ’…

πŸ‘‘ OPTIONS πŸ‘‘

  • --level LEVEL β€” which verification level to run. Default is metadata for a btrfs target, and stream (the sealed-checksum check) for a raw target. The reasoning is kinda cute honestly: a raw backup's integrity is whether its stored bytes still match what was written, so a bare verify on a raw target actually reads the stream rather than reporting a hollow pass from just looking at a directory listing. πŸ™ˆ Valid levels:
    • metadata β€” a fast structural check that each backup is a real backup artifact, not merely a name-shaped entry. For a btrfs target: confirms each entry is a received read-only subvolume (an interrupted receive that left a plain directory FAILS rather than passing), and an entry whose received status can't be confirmed without privilege is reported unverifiable rather than failed. For a raw target: confirms an authoritative .meta sidecar is present, and when a snapshot records an incremental parent, that the parent actually exists among the backups (a recorded-but-absent parent is an unrestorable chain break and FAILS). This one is fast and non-destructive; it does not read stream/file data (use stream or full for that).
    • stream β€” for a btrfs target, verify that a btrfs send stream can be generated (uses btrfs send --no-data to test stream generation without transferring file data, validating that snapshot metadata is intact). For a raw target, recompute the stored stream's sha256 and compare it to the checksum sealed in its .meta sidecar, detecting at-rest corruption.
    • full β€” for a btrfs target, a complete restore test to a temporary location: it actually restores the target snapshot with a full btrfs send (reading every data block, so btrfs's own checksums catch at-rest corruption) and verifies the restored subvolume is valid. The most thorough check, but the slowest β€” and for a remote backup it pulls the whole snapshot over the network. Requires --temp-dir on a local btrfs filesystem for remote backups, and root or passwordless sudo (it runs btrfs receive). If the restore test can't run β€” no privilege, or the target doesn't fit in the temp filesystem β€” the snapshot is reported unverifiable, not failed. For a raw target, full performs the same sealed-checksum verification as stream.
  • --snapshot NAME β€” verify only the named snapshot. Mutually exclusive with --all. (pick ONE bestie, they're not friends.)
  • --all β€” verify EVERY snapshot at the backup location. The stream and full levels only check the latest snapshot by default (fast!); --all verifies the whole chain. The metadata level and raw targets already check all snapshots, so --all is a no-op there. Mutually exclusive with --snapshot.
  • --temp-dir PATH β€” temporary directory for full verification. Must be on a btrfs filesystem. Required for full verification of remote backups. Created if it does not exist; without it, the temporary directory is made inside the backup location, which must exist.
  • --no-cleanup β€” do not delete restored snapshots after full verification. super useful for inspection or debugging πŸ”
  • --prefix PREFIX β€” only verify snapshots matching the given prefix.
  • --ssh-sudo β€” use sudo for btrfs commands on the remote host.
  • --ssh-key FILE β€” SSH private key file for authentication.
  • --ssh-auth-sock PATH β€” explicit ssh-agent socket (overrides auto-discovery; useful under sudo).
  • --ssh-host-key-policy POLICY β€” host-key verification for this run: accept-new (default) or strict.
  • --fs-checks MODE β€” filesystem verification mode. Valid values:
    • auto β€” (default) warn about issues but continue operation.
    • strict β€” error out on filesystem check failures.
    • skip β€” bypass all filesystem verification checks.
  • --no-fs-checks β€” skip btrfs subvolume verification checks. It's an alias for --fs-checks=skip. Useful when verifying backup directories which are regular directories, not subvolumes.
  • --json β€” output results in JSON format for scripting and automation. for the girlies who pipe things πŸ€–
  • -q, --quiet β€” suppress progress output.
  • --skip-remote-lock β€” proceed even if a lock cannot be recorded on the remote target. > Only safe when nothing else can prune this target during the run. (like, genuinely. be careful. πŸ’€)
  • --timestamp-format FMT β€” strftime format for parsing snapshot timestamps in direct mode (defaults to the config's [global] timestamp_format, else the built-in).

πŸ” VERIFICATION LEVELS πŸ”

πŸ“ Metadata (Fast)

Checks performed, per snapshot:

  • Structural validity β€” that the entry is a REAL backup artifact: a received read-only btrfs subvolume (non-empty received UUID), or a raw stream with an authoritative .meta sidecar. A plain directory (e.g. an interrupted receive) FAILS; an entry whose backup identity cannot be confirmed without privilege is reported unverifiable, not failed β€” a good backup is never failed merely because the environment could not prove it. 🫢
  • Authoritative incremental-parent continuity β€” for a raw snapshot that records its parent's name, that the parent actually exists among the backups (a recorded-but-absent parent is an unrestorable chain break and FAILS). btrfs snapshots carry no recorded parent name at this level, so their chain is validated by full verification.

This level is fast and non-destructive and can verify hundreds of snapshots in seconds ⚑; it does not read stream/file data.

🌈 Stream (Medium)

In addition to metadata checks:

  • Generates btrfs send stream with --no-data flag
  • Validates stream header and metadata integrity
  • Does not transfer actual file data

This level catches corruption in snapshot metadata that metadata-only checks might miss. sneaky little bugs, caught. πŸ‘‘

🧚 Full (Thorough)

Performs an actual restore of the target snapshot:

  • Full btrfs send of the target into a temp subvolume (no incremental parent needed β€” the backup's received subvolumes are already fully materialized), reading every data block
  • Verifies the restored path is a valid btrfs subvolume
  • Reports unverifiable (not failed) if the environment cannot run the test (no root/sudo, or the target does not fit in the temp filesystem)
  • Cleans up the restored subvolume afterward (unless --no-cleanup); a user-supplied --temp-dir is never removed, only the restored subvolumes within it

This is the definitive test that a backup can be restored. Requires root or passwordless sudo, and --temp-dir on a local btrfs filesystem for remote backups. it's giving main character energy, but it's also the slowest. 😭

🌸 Raw targets (sealed checksum)

For a raw:// or raw+ssh:// target, the stream and full levels recompute each stored stream's sha256 and compare it to the checksum sealed in the stream's .meta sidecar. Every stream is checked (not just the latest). Per-snapshot status is one of:

  • ok β€” the stream matches its sealed checksum (intact). πŸ’–
  • corrupt β€” the stream on disk no longer matches (fails; exit 1).
  • error β€” the stream could not be read to hash it (fails; exit 1).
  • unverifiable β€” no sha256 checksum was recorded (a legacy backup); not a failure, but reported explicitly rather than as a silent pass.

For a raw+ssh:// target the sha256 is recomputed on the (untrusted) remote host, so an ok verdict evidences at-rest consistency, not authenticity β€” a compromised target could forge a match. 😳

Verify a locally-mounted raw:// copy for tamper-evidence.

πŸ’€ VERDICT AND COUNTS πŸ’€

Every run reports one of three verdicts (the verdict field in --json; the final line in human output):

  • pass β€” every snapshot that was checked verified successfully.
  • unverifiable β€” no failures, but one or more snapshots could not be confirmed (an environmental limit, e.g. no privilege or a legacy backup with no recorded checksum). This is NOT a failure; a good backup is never reported bad because it could not be checked. πŸ’œ
  • fail β€” at least one snapshot failed, or a run-level error occurred.

The summary counts verified (positively confirmed), failed, and unverifiable separately β€” an unverifiable snapshot is never counted as verified. It also states how many snapshots were checked of how many are available; when only a subset was checked (the latest, at stream/full level), it hints to pass --all to verify the whole chain. periodt. πŸ’…


⭐ EXIT STATUS ⭐

  1. 0 β€” verdict pass or unverifiable (no failure detected; an environmental inability to verify does not raise an alarm).
  2. 1 β€” verdict fail β€” one or more verifications failed.
  3. 2 β€” run-level error (bad arguments, no snapshots found, temp directory unusable, etc.).

and bestie, there's more β€”

🌈 EXAMPLES 🌈

Lowkey the best part, bestie β€” here's every vibe of verify you could possibly want ✨

  • Quick metadata check of local backup:
btrfs-backup-ng verify /mnt/backup/home
  • Verify remote backup over SSH:
btrfs-backup-ng verify ssh://backup@server:/backups/home --ssh-sudo
  • Stream integrity check:
btrfs-backup-ng verify /mnt/backup/home --level stream
  • Full restore test:
btrfs-backup-ng verify /mnt/backup/home --level full --temp-dir /mnt/test
  • Full verification of remote backup:
btrfs-backup-ng verify ssh://server:/backups/home --level full --temp-dir /mnt/test
  • Verify a raw target (checks the sealed sha256 of every stream):
btrfs-backup-ng verify raw:///mnt/usb/backups
  • Verify a remote raw target over SSH:
btrfs-backup-ng verify raw+ssh://backup@server:/backups --ssh-sudo
  • Verify specific snapshot:
btrfs-backup-ng verify /mnt/backup/home --snapshot home-20260104-120000
  • Verify the ENTIRE chain (every snapshot), not just the latest:
btrfs-backup-ng verify /mnt/backup/home --level stream --all
  • JSON output for automation:
btrfs-backup-ng verify /mnt/backup/home --json

πŸ‘‘ OUTPUT πŸ‘‘

So when you run verify, it shows you a table of per-snapshot results, and every single one gets a status that's very clear about how it's doing: PASS (green 🟒), UNVERIFIABLE (yellow 🟑), or FAIL (red πŸ”΄). And then after the table comes a summary with the verified / failed / unverifiable counts, the checked-of-available count, and the verdict. Chef's kiss, no notes πŸ’…

When you throw --json in there, the output is a JSON object containing:

  • verdict: the authoritative top-level result β€” pass, unverifiable, or fail. Monitoring should gate on this rather than re-deriving from counts. Like fr fr, just read the verdict, don't do math, trust the vibe check ✨
  • level: Verification level used
  • location: Backup location
  • duration_seconds: Total verification time
  • summary: verified, failed, unverifiable, checked, and available counts (passed and total are retained as back-compat aliases: passed = not-failed, total = checked)
  • results: Array of individual snapshot results, each with a status of ok/failed/unverifiable
  • errors: Array of run-level error messages

πŸ¦‹ AUTOMATION πŸ¦‹

Okay bestie, if you want automated backup verification in scripts or cron, you gate on the verdict field. Periodt. That's the whole strategy πŸ’–

#!/bin/bash
report=$(btrfs-backup-ng verify /mnt/backup/home --all --json)
verdict=$(printf '%s' "$report" | jq -r .verdict)
if [ "$verdict" = "fail" ]; then
    printf '%s' "$report" | mail -s "Backup verification FAILED" admin@example.com
elif [ "$verdict" = "unverifiable" ]; then
    printf '%s' "$report" | mail -s "Backup could not be fully verified" admin@example.com
fi

🫢 SEE ALSO 🫢


And that's the whole page, bestie β€” this one's from the btrfs-backup-ng fam, dated July 2026, and it's the BTRFS-BACKUP-NG-VERIFY(1) manual, iconic as always πŸ’…βœ¨ Go verify something and feel like the main character πŸ‘‘

πŸ“¦ where this page comes from