Skip to content

legacy client: work with a borg 1.x "borg serve" - #10420

Merged
ThomasWaldmann merged 1 commit into
borgbackup:masterfrom
ThomasWaldmann:from-borg1-borg14-serve
Sep 24, 2026
Merged

ThomasWaldmann merged 1 commit into
borgbackup:masterfrom
ThomasWaldmann:from-borg1-borg14-serve

Conversation

@ThomasWaldmann

Copy link
Copy Markdown
Member

--from-borg1 via ssh:// (e.g. borg transfer --from-borg1 --other-repo ssh://...) did not work with a real borg 1.x borg serve on the remote host. Every command failed with rc 82 RPC method close is not valid. The testsuite only ever ran the legacy client against borg 2's own legacy borg serve, so this went unnoticed.

Causes

  1. After open, the client called info(), which borg 1.x servers do not have (Borg server is too old for info).
  2. The cleanup then called close(), which always sent the close RPC. borg 1.x servers do not have that either, and the resulting error masked the first one.
  3. get_manifest is also missing on borg 1.x servers.
  4. borg 1.x servers pack bytes into the msgpack "raw" type, which the borg 2 client unpacks to str (surrogateescape). So e.g. the repository id and object data arrived as str, and loading the key failed with Unsupported payload type.

Fix

In LegacyRemoteRepository, for a borg 1.x server (negotiated server version < 2.0.0a1):

  • use repository version 1 instead of calling info() (borg 1.x only serves v1 repositories);
  • do not send the close RPC (borg 1.x closes the repository when stdin gets closed);
  • get the manifest object via get, like LegacyRepository.get_manifest() does;
  • convert the results of open, get, list, scan and load_key back to bytes (surrogateescape round-trips exactly).

Borg 2 servers are handled as before.

Testing

  • Real borg 1.4.5 borg serve on NetBSD 11 (remote side run via a fake ssh that executes the command locally): repo-list, version, repo-create --other-repo and transfer, all with --from-borg1, for repokey and keyfile repositories. Extracting from the transferred borg 2 repository gives the original data, and the borg 1.x repository lock is released.
  • New test test_remote_borg1_server: it emulates a borg 1.x server (the legacy server with borg 1.x msgpack packing, version 1.4.5, no info/close/get_manifest, closing the repository at EOF). Without the fix it fails exactly like the real borg 1.4 case. Also new: test_bytes_from_borg1.
  • Full suite locally (macOS): all pass except test_migrate_lock_alive (known local macFUSE issue, fails on master too).

🤖 Generated with Claude Code

--from-borg1 via ssh:// (e.g. borg transfer from a borg 1.x repository)
failed with a borg 1.x "borg serve" on the remote host:

- the client called info() after open, which borg 1.x servers do not
  have ("Borg server is too old for info"),
- then close() sent the close RPC, which borg 1.x servers do not have
  either ("RPC method close is not valid"), masking the first error,
- get_manifest is also missing on borg 1.x servers,
- borg 1.x servers pack bytes into the msgpack "raw" type, which the
  client unpacks to str, so e.g. the repository id and object data
  arrived as str.

For borg 1.x servers, the client now uses repository version 1 (the only
version borg 1.x serves), does not send the close RPC (borg 1.x closes
the repository when stdin gets closed), gets the manifest object via get
and converts the bytes results back to bytes.

Tested with a real borg 1.4.5 "borg serve": repo-list, version,
repo-create --other-repo and transfer with --from-borg1, repokey and
keyfile mode. The testsuite emulates a borg 1.x server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.18519% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.41%. Comparing base (db0c4ac) to head (d1c7771).
⚠️ Report is 1 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/borg/legacy/remote.py 85.18% 3 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #10420      +/-   ##
==========================================
+ Coverage   88.38%   88.41%   +0.02%     
==========================================
  Files         103      103              
  Lines       19029    19051      +22     
  Branches     2961     2967       +6     
==========================================
+ Hits        16819    16844      +25     
+ Misses       1538     1535       -3     
  Partials      672      672              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@ThomasWaldmann
ThomasWaldmann merged commit 3ef3441 into borgbackup:master Sep 24, 2026
25 of 26 checks passed
@ThomasWaldmann
ThomasWaldmann deleted the from-borg1-borg14-serve branch September 24, 2026 19:04
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.

1 participant