Combine flatMap can result in values after failure - bug?

Hi, I'm seeming some odd behaviour with failure handling and the flatMap operator. It seems that if a Publisher inside a flatMap fails, this doesn't result in downstream publishers entering a failed state where no more values are propagated. Instead, the downstream publishers will propagate the failure and then continue to propagate values as well.

Here's a quick example:

import Combine

enum IntError: Error {
    case badInt
}

let subject = PassthroughSubject<Int, IntError>()

subject
    .flatMap { x -> AnyPublisher<Int, IntError> in
        if x == 2 {
            return Publishers.Fail(error: IntError.badInt).eraseToAnyPublisher()
        } else {
            return Just(x).setFailureType(to: IntError.self).eraseToAnyPublisher()
        }
    }
    .map { $0 * 2 }
    .sink(
        receiveCompletion: { completion in
            switch completion {
            case .failure:
                print("Failure")
            case .finished:
                print("Finished")
            }
        },
        receiveValue: { value in
            print("Value: \(value)")
        })

subject.send(1)
subject.send(2)
subject.send(3)

This results in:

Value: 2
Failure
Value: 6

Coming from the Rx and ReactiveSwift world, this seems like a bug. The failure should cause the flatMap to enter a failed state. Or at the very least cause the downstream map to enter a failed state. Does Combine deliberately behave differently, as if the downstreams are created anew when a flatMap creates a new Publisher, or is this a bug?

That definitely seems like a bug, can you please file a feedback on that?

Thanks for the reply Phillippe. I've filed a feedback, it's FB7039925.

1 Like

I know this is years later, but would it also be possible to use switchToLatest() in place of a flatMap?