Errors in the stream switched using flatMap are not involved upstream in Combine framework.
Tags: ios, combine, swift
Published: 2020-11-29 07:33:17

---
title: Errors in the stream switched using flatMap are not involved upstream in Combine framework.
published: true
description: 
tags: ios, Combine, swift
series: 
//cover_image: https://direct_url_to_image.jpg
---


The Publisher will terminate the stream in case of an error. However, if the Publisher switched by flatMap fails, the upstream before the switch does not terminate.

(This would be a big difference from RxSwift.)

## Using flatMap sample

```swift
import Foundation
import Combine

let cancelable = (1...3).publisher
    .handleEvents(receiveOutput: {
        print("🥷 handle output: \($0)")
    }, receiveCompletion: { _ in
        print("🥷 handle completion:")
    }, receiveCancel: {
        print("🥷 handle cancel:")
    })
    .setFailureType(to: NSError.self)
    .flatMap { value -> Future<String, NSError> in
        print("🍏 flatMap: \(value)")
        return Future<String, NSError> {
            guard value == 1 else {
                $0(.failure(NSError(domain: "test", code: 1)))
                return
            }

            $0(.success("\(value)"))
        }
    }
    .sink(receiveCompletion: {
        switch $0 {
        case .finished:
            print("🍎 sink finished:")
        case .failure(let error):
            print("🍎 sink failure:", error)
        }
    }, receiveValue: {
        print("🍎 sink received: \(String(describing: $0)) 🎉")
    })
```

This code has the following output:

```
🥷 handle output: 1
🍏 flatMap: 1
🍎 sink received: 1 🎉
🥷 handle output: 2
🍏 flatMap: 2
🍎 sink failure: Error Domain=test Code=1 "(null)"
🥷 handle output: 3
🥷 handle completion:
```

Notice the 🥷 emoji; despite the sink failure, the output will see that the element is handled 3 and even sent to completion.

## Using PasshtoughSubject & flatMap sample

Of course, using PassthroughSubject doesn't change the result.

```swift
import Foundation
import Combine

let subject = PassthroughSubject<Int, NSError>()

let cancelable = subject
    .handleEvents(receiveOutput: {
        print("🥷 handle output: \($0)")
    }, receiveCompletion: { _ in
        print("🥷 handle completion:")
    }, receiveCancel: {
        print("🥷 handle cancel:")
    })
    .flatMap { value -> Future<String, NSError> in
        print("🍏 flatMap: \(value)")
        return .init {
            guard value == 1 else {
                $0(.failure(NSError(domain: "test", code: 1)))
                return
            }

            $0(.success("\(value)"))
        }
    }
    .sink(receiveCompletion: {
        switch $0 {
        case .finished:
            print("🍎 sink finished:")
        case .failure(let error):
            print("🍎 sink failure:", error)
        }
    }, receiveValue: {
        print("🍎 sink received: \(String(describing: $0)) 🎉")
    })

subject.send(1)
subject.send(2)
subject.send(3)
subject.send(completion: .finished)
```

This code has the following output:

```
🥷 handle output: 1
🍏 flatMap: 1
🍎 sink received: 1 🎉
🥷 handle output: 2
🍏 flatMap: 2
🍎 sink failure: Error Domain=test Code=1 "(null)"
🥷 handle output: 3
🥷 handle completion:
```

After all, the upstream doesn't care if the downstream switched stream fails. This may cause the stream execution process to continue unnecessarily.

My guess is that to account for this, we would have to control it with subscriptions.