tryCatch followed by retry creates a retain cycle?

It looks like having tryCatch + retry will create a retain cycle.

Here is the repo demonstrating the issue:

Steps to reproduce:
  1. Launch App - CombineRetryDemo

  2. Tap - "Load HTML" button

  3. Wait for prints in console. For example: completed finished

  4. Tap "Back" button

  5. Run Debug Memory Graph

Expected:
HTMLViewController is deallocated and de inited is printed in console
subscription is canceled and all the combine publishers are deallocated

Actual:
HTMLViewController is deallocated and de inited is printed in console
Retry and TryCatch are not deallocated and create retain cycle.

Memory graph

Context:
For our use case we are using a sequence of Combine operators to make a request to a server. In the case where the request fails (server responds with expired token/invalid etc) we want to refresh our token inside the .tryCatch and retry the entire sequence from the beginning.

After experimenting we found that replacing retry by having all of our business logic inside the .tryCatch doesn't create a retain cycle but requires us to duplicate our sequence of operators. Is there a better approach we can use?
Here in your example:
Code Block swift
URLSession.shared
.dataTaskPublisher(for: URL(string: "https://www.apple.com/")!)
.tryCatch { _ in
URLSession.shared
.dataTaskPublisher(for: URL(string: "https://www.example.com/")!)
}
.retry(1)
.map {
String(decoding: $0.data, as: UTF8.self)
}
.sink(
receiveCompletion: { print("completed \($0)") },
receiveValue: { print("value \($0)") })
.store(in: &cancellables)

I see the leak of Combine.Publishers.Retry and Combine.Publishers.TryCatch
every time this code runs through the successful path. I've tried the failure path by changing apple.com to zapple.com - a non-existing domain, leak still appears.

Looks like retry is source of the leak and tryCatch is the cause of it.
When I remove retry or .tryCatch - no leaks. Is this a Combine bug or incorrect use of Combine?

Even simpler version:

Code Block
        CurrentValueSubject<String,Error>("apple")
            .tryCatch { _ in
                CurrentValueSubject<String,Error>("pear")
            }
            .retry(1)
            .sink(
                receiveCompletion: { print("completed \($0)") },
                receiveValue: { print("value \($0)") })
            .store(in: &cancellables)

leaks the same
tryCatch followed by retry creates a retain cycle?
 
 
Q