Skip to content

Commit 560a596

Browse files
committed
fix(libstore/filetransfer): prevent double callback invocation on interrupt during retry
Fix a race condition where interrupting a download (via Ctrl-C) during a retry attempt could cause a crash. When `enqueueItem()` throws because the download thread is shutting down, the exception would propagate without setting `done=true`, causing the `TransferItem` destructor to invoke the callback a second time. This triggered an assertion failure in `Callback::rethrow()` with: `Assertion '!prev' failed` and the error message `cannot enqueue download request because the download thread is shutting down`. The fix catches the exception from `enqueueItem()` and calls `fail()` to properly complete the transfer, ensuring the callback is invoked exactly once.
1 parent da637a0 commit 560a596

File tree

1 file changed

+8
-1
lines changed

1 file changed

+8
-1
lines changed

src/libstore/filetransfer.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,14 @@ struct curlFileTransfer : public FileTransfer
598598
decompressionSink.reset();
599599
errorSink.reset();
600600
embargo = std::chrono::steady_clock::now() + std::chrono::milliseconds(ms);
601-
fileTransfer.enqueueItem(shared_from_this());
601+
try {
602+
fileTransfer.enqueueItem(shared_from_this());
603+
} catch (const nix::Error & e) {
604+
// If enqueue fails (e.g., during shutdown), fail the transfer properly
605+
// instead of letting the exception propagate, which would leave done=false
606+
// and cause the destructor to attempt a second callback invocation
607+
fail(std::move(exc));
608+
}
602609
} else
603610
fail(std::move(exc));
604611
}

0 commit comments

Comments
 (0)