Skip to content

fix: handle Borg 2 repo-info and info output without cache stats or encryption mode - #2633

Merged
m3nu merged 1 commit into
masterfrom
fix/2613-borg2-info-keyerror
Nov 15, 2026
Merged

m3nu merged 1 commit into
masterfrom
fix/2613-borg2-info-keyerror

Conversation

@m3nu

@m3nu m3nu commented Nov 15, 2026

Copy link
Copy Markdown
Contributor

Description

BorgInfoRepoJob.process_result (Add Existing Repository) and BorgInfoArchiveJob.process_result (archive Refresh) read keys that Borg 2 does not emit and raised KeyError:

  • cache is {"path": ...} (or {}) with no stats.
  • From 2.0.0b22, encryption is {"encryption": <cipher>, "id_hash": ...}, plus "keyfile": <path> when the key is stored as a keyfile, instead of {"mode": ...}.
  • Archive stats has no deduplicated_size for an existing archive.

With Borg 2, adding an existing repo failed with "Unable to add your repository." and left a repo row behind, so a retry reported the repo as already added. Archive refresh never succeeded.

Changes:

  • Both handlers only read repo size stats when cache.stats is present. Without it the repo sizes stay empty and the repo tab shows "N/A", as it already does.
  • Archive refresh keeps the archive size recorded at create time when Borg does not report deduplicated_size.
  • A new encryption_mode() helper in info_repo.py returns the value stored in RepoModel.encryption:
    • mode as before when Borg reports it (Borg 1 and Borg 2 up to b21);
    • none for the plaintext ciphers none, none-sha256 and none-blake3 (b22–b24);
    • otherwise repokey-<cipher> or keyfile-<cipher>, for example repokey-chacha20-poly1305.
  • The encryption value is worked out before the repo row is created, so an unexpected shape no longer leaves a row behind.

Why a synthesised mode instead of the bare cipher name the issue suggests: RepoModel.encryption is compared with 'none' in borg_job.py, change_passphrase.py, init.py and info_repo.py, and "Change passphrase" is only offered when it starts with repokey (repo_tab.py). A bare chacha20-poly1305 would disable Change passphrase for every b22+ repo. Keeping the Borg 1 shape needs no change in those readers.

Things to be aware of:

  • The stored value does not include the id hash, so the repo tab shows repokey-chacha20-poly1305 for both sha256 and blake3 repos.
  • Borg 2 authenticated repos are stored as repokey-authenticated-sha256 / -blake3, so Change passphrase is offered for them. With Borg 1 it is not (authenticated fails the repokey check). Borg 2.0.0b25 accepted key change-passphrase on such a repo.
  • When repo creation is ported to the b22+ repo-create --encryption values, init.py should store the same form, or created and added repos will differ.
  • If Borg returns non-JSON output with exit code 0, adding the repo now fails. Before, it added a repo row without encryption info.

Related Issue

Fixes #2613

Motivation and Context

See above. Not included, as the issue says: the missing None check after ArchiveModel.get_or_none(...) in info_archive.py, and the repo-create encryption choices for b22+.

How Has This Been Tested?

On macOS. Unit tests run with Borg 1.4.3 (nox default) and a mocked Popen.

  • New fixtures repo_info_v2_* and info_v2_* are real borg repo-info --json and borg info --json output from Borg 2.0.0b25, with paths, host and user replaced by placeholders and the archive id and duration set to match the test data.
  • tests/unit/test_repo.py::test_info_repo_process_result: seven shapes (Borg 1, Borg 2 with mode, b25 repokey, b25 keyfile, none-sha256, none, Borg 1 none), checking the stored mode, sizes and whether the passphrase is written to the keyring.
  • tests/unit/test_repo.py::test_repo_add_existing_borg2: the Add Existing Repository dialog end to end with the b25 fixture.
  • tests/unit/test_archives.py::test_refresh_archive_info_borg2: Refresh keeps the archive size and updates the duration.
  • With the two source files reverted, the five Borg 2 cases and both GUI tests fail with the KeyErrors above; the Borg 1 cases pass.
  • Full unit suite: 692 passed, 8 skipped, 1 deselected (test_keyring_darwin.py::test_keyring_non_ascii_repo, which writes to the real login keychain).
  • Real Borg 2.0.0b25 output from four throwaway repos (repokey, keyfile, authenticated-sha256, authenticated-blake3) was fed through both handlers: stored modes were repokey-chacha20-poly1305, keyfile-aes256-ocb, repokey-authenticated-sha256 and repokey-authenticated-blake3, sizes stayed empty, archive sizes were kept and nothing raised.

Not tested:

  • No Borg 2.0.0b10–b24 binary was run. Those shapes (mode up to b21, the plaintext ciphers at b22–b24) come from reading the Borg source.
  • The Vorta GUI was not run against a real Borg 2 repo; real output was fed to the handlers directly.
  • Integration tests were not run locally.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • I have read the CONTRIBUTING guide.
  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

I provide my contribution under the terms of the license of this repository and I affirm the Developer Certificate of Origin.

…ncryption mode

Borg 2 reports `cache` without `stats`, archive `stats` without
`deduplicated_size`, and from 2.0.0b22 `encryption` as a cipher name
instead of a mode. BorgInfoRepoJob and BorgInfoArchiveJob raised
KeyError on this, so adding an existing Borg 2 repo failed and left an
orphan repo row, and archive refresh never completed.

Skip missing stats, keep the archive size recorded at create time, and
map the Borg 2 encryption info to a Borg 1 style mode
(`repokey-<cipher>`, `keyfile-<cipher>` or `none`). Add fixtures based on
real 2.0.0b25 output.

Fixes #2613
@m3nu
m3nu merged commit fdac41f into master Nov 15, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Borg 2: KeyError in repo-info and archive info result handlers

1 participant