Repository.close(): don't mask the original exception when unwinding with buffered chunks - #10013
Draft
ThomasWaldmann wants to merge 1 commit into
Draft
Repository.close(): don't mask the original exception when unwinding with buffered chunks#10013ThomasWaldmann wants to merge 1 commit into
ThomasWaldmann wants to merge 1 commit into
Conversation
…with buffered chunks When a borg command aborts with chunks still buffered in the PackWriter (e.g. an exception mid-create between pack flushes), the "with repository:" unwind called close(), whose "PackWriter has unflushed chunks" assertion raised AssertionError and masked the original exception. Also, buffered chunks left F_PENDING entries in the chunk index, which the close()-time index persist would trip over. Fix: on exception unwind, Repository.__exit__ now drops the buffered pieces and their still-pending index entries via the new PackWriter._drop_buffered() (also reused in flush()'s store-failure path), so the original exception propagates unmasked and no F_PENDING entries are persisted. The never-stored chunks die with the aborted operation. On a clean close, the assertion still catches a forgotten flush(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ThomasWaldmann
marked this pull request as draft
August 2, 2026 14:48
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #10013 +/- ##
=======================================
Coverage 86.10% 86.10%
=======================================
Files 96 96
Lines 17326 17332 +6
Branches 2649 2650 +1
=======================================
+ Hits 14918 14924 +6
Misses 1667 1667
Partials 741 741 ☔ View full report in Codecov by Harness. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Repository.close()asserts that the PackWriter has no unflushed chunks. When a borg command aborts with chunks still buffered (e.g. an exception mid-borg createbetween pack flushes), thewith repository:unwind callsclose()and this assertion raisesAssertionError, masking the original exception. Additionally, the buffered chunks leftF_PENDINGentries in the chunk index, which the close()-timewrite_chunkindex_to_repowould trip over (it asserts no entry is still pending).Reproduce: open a
Repository,put()one small chunk (below the pack size limit), raise inside the with-block — the AssertionError replaces the real error.Fix
PackWriter._drop_buffered(): empties the piece buffer and deletes the still-pending index entries for the buffered chunks.flush()'s store-failure path now reuses it instead of duplicating the same drop logic inline.Repository.__exit__calls it when unwinding an exception, beforeclose(). The never-stored chunks die with the aborted operation: the original exception propagates unmasked, and noF_PENDINGentries reach the persisted chunk index.close()is unchanged: on a clean close it still catches a genuinely forgottenflush().__exit__is the only place that knows whether we are unwinding, so the drop decision lives there.Tests
test_exception_unwind_drops_buffered_chunks: the repro above; asserts the originalValueError(notAssertionError) propagates, and after reopening the buffered chunk is neither in the chunk index nor readable.test_close_with_unflushed_chunks_asserts: documents that a clean exit with buffered chunks still trips the assertion.All repository and cache tests pass; ruff clean.
🤖 Generated with Claude Code