# Typed throws do not infer type in generic type-throwing functions

**URL:** <https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036>\
**Category:** Using Swift\
**Tags:** generics, concurrency, typed-throws\
**Created:** [April 2, 2025, 6:34pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036 "2025-04-02T18:34:50Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![hibernat](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hibernat/32/31657_2.png) [@hibernat](https://forums.swift.org/u/hibernat)\
**Post date:** [April 2, 2025, 6:34pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/1 "2025-04-02T18:34:50Z")

</div>

Typed throws in generic function are not typed throws

```swift
@Sendable
public func withSingleTaskInThrowingTaskGroup<Returning: Sendable, ThrowsError: Error>(
    cancellationError: ThrowsError,
    perform: @escaping @Sendable () async throws(ThrowsError) -> Returning
) async throws(ThrowsError) -> Returning {
    do {
        return try await withThrowingTaskGroup(of: Returning.self, returning: Returning.self) { taskGroup in
            taskGroup.addTask(operation: perform)
            return try await taskGroup.next()!
        }
    } catch {
        switch error {
        case let error as ThrowsError: throw error
        default: throw cancellationError
        }
    }
}

```

This function should throw only `ThrowsError` type, however, when used, compiler says _Thrown expression type 'any Error' cannot be converted to error type 'XXX'_

---

<div class="post-metadata">

**Author:** ![grynspan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/grynspan/32/15315_2.png) [@grynspan](https://forums.swift.org/u/grynspan)\
**Post date:** [April 2, 2025, 7:12pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/3 "2025-04-02T19:12:49Z")

</div>

~~This is unsafe as a `Task` may also throw an error of type `CancellationError` independent of the body closure.~~

☕

---

<div class="post-metadata">

**Author:** ![hibernat](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hibernat/32/31657_2.png) [@hibernat](https://forums.swift.org/u/hibernat)\
**Post date:** [April 2, 2025, 7:14pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/4 "2025-04-02T19:14:49Z")

</div>

You are not at the point. The generic function is declared (and compiled) as throwing `ThrowsError`, however when used, compiler ignores the exception type.

---

<div class="post-metadata">

**Author:** ![grynspan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/grynspan/32/15315_2.png) [@grynspan](https://forums.swift.org/u/grynspan)\
**Post date:** [April 2, 2025, 7:24pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/7 "2025-04-02T19:24:15Z")

</div>

> [@Danny](#):
>
> That can only happen if you use `Task.checkCancellation()`, in which case, typed throws is not possible.

Yup, you're right—`Task` does _not_ currently throw `CancellationError` on its own and I was misremembering. Need more coffee!

> [@Danny](#):
>
> False!
> 
> ```swift
> struct E: Error { }
> func f() async throws(E) {
> try await withSingleTaskInThrowingTaskGroup(cancellationError: E()) {
> () throws(_) in throw E()
> }
> }
> 
> ```

I believe @hibernat is not explicitly writing `throws` inside the body of the closure, in which case in Swift 6 mode the compiler does _not_ infer an error type for the closure (beyond `any Error`). This is by design. See the relevant section in [SE-0413](https://github.com/swiftlang/swift-evolution/blob/3cab5308fd51a4791607cc6276f6eed1889fadf9/proposals/0413-typed-throws.md#closure-thrown-type-inference).

---

<div class="post-metadata">

**Author:** ![hibernat](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hibernat/32/31657_2.png) [@hibernat](https://forums.swift.org/u/hibernat)\
**Post date:** [April 2, 2025, 7:46pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/8 "2025-04-02T19:46:20Z")

</div>

Thanks, that is great response. However, why is this function accepted by the compiler? There is no inference needed, the exception type is declared, required is the same exception type for the `perform` throwing function/closure and the exception thrown by the function.

Watch this (compiler error (type is any Error)):

```swift
struct E: Error { }

@Sendable
func g() async throws(E) {
    throw E()
}

func f() async throws(E) {
    do throws(E) {
        try await withSingleTaskInThrowingTaskGroup(cancellationError: E()) {
            try await g()
        }
    } catch {
        
    }
}

```

---

<div class="post-metadata">

**Author:** ![grynspan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/grynspan/32/15315_2.png) [@grynspan](https://forums.swift.org/u/grynspan)\
**Post date:** [April 2, 2025, 7:52pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/9 "2025-04-02T19:52:31Z")

</div>

From what I see locally, this fails to compile in a way I'd expect:

```swift
func f() async throws(E) {
  do throws(E) {
    try await withSingleTaskInThrowingTaskGroup(cancellationError: E()) {
      // ^ ^ ^ Thrown expression type 'any Error' cannot be converted to error type 'E'
      try await g()
    }
  } catch {

  }
}

```

This is because you didn't explicitly write `() throws(E) in` in the body of the closure you passed to `withSingleTaskInThrowingTaskGroup()`, which causes it to infer the type of the closure as throwing `any Error`, which is then incompatible with the expected type `E` (which is inferred from the explicit `E()` you passed as an argument to `withSingleTaskInThrowingTaskGroup()`.)

If I add `() throws(E) in`, it compiles as expected:

```swift
func f() async throws(E) {
  do throws(E) {
    try await withSingleTaskInThrowingTaskGroup(cancellationError: E()) { () throws(E) in
      try await g()
    }
  } catch {

  }
}

```

---

<div class="post-metadata">

**Author:** ![hibernat](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hibernat/32/31657_2.png) [@hibernat](https://forums.swift.org/u/hibernat)\
**Post date:** [April 2, 2025, 7:57pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/10 "2025-04-02T19:57:39Z")

</div>

OK. I accept this explanation, with respect to the design (SE-0413). Thanks again!

---

<div class="post-metadata">

**Author:** ![grynspan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/grynspan/32/15315_2.png) [@grynspan](https://forums.swift.org/u/grynspan)\
**Post date:** [April 2, 2025, 8:05pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/13 "2025-04-02T20:05:44Z")

</div>

I'm aware. 🙂 Whether you write `throws(E)` or `throws(_)` is not really the high-order bit here.

---

<div class="post-metadata">

**Author:** ![Danny](https://avatars.discourse-cdn.com/v4/letter/d/848f3c/32.png) [@Danny](https://forums.swift.org/u/Danny)\
**Post date:** [April 2, 2025, 8:09pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/14 "2025-04-02T20:09:04Z")

</div>

(post deleted by author)

---

<div class="post-metadata">

**Author:** ![hibernat](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hibernat/32/31657_2.png) [@hibernat](https://forums.swift.org/u/hibernat)\
**Post date:** [April 2, 2025, 9:12pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/16 "2025-04-02T21:12:40Z")

</div>

I highly appreciate your responses. This code does not compile. This is also "works as designed"?

```swift
struct E: Error { }

func g() async throws(E) -> Int {
    throw E()
}

do throws(E) {
    async let h = try g()
    try await h
} catch {

}

```

---

<div class="post-metadata">

**Author:** ![grynspan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/grynspan/32/15315_2.png) [@grynspan](https://forums.swift.org/u/grynspan)\
**Post date:** [April 5, 2025, 9:07pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/17 "2025-04-05T21:07:51Z")

</div>

Looks like it's an issue with `async let`. I'm afraid I don't have more information than that. Please file a GitHub issue against Swift about it?

---

<div class="post-metadata">

**Author:** ![hibernat](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hibernat/32/31657_2.png) [@hibernat](https://forums.swift.org/u/hibernat)\
**Post date:** [April 5, 2025, 10:05pm UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/18 "2025-04-05T22:05:21Z")

</div>

Danny responded:

> [@On another topic](https://forums.swift.org/t/79081/2):
>
> ... It may eventually get fixed. I found a report from last year: [Async let does not preserve typed throw · Issue #76169 · swiftlang/swift · GitHub](https://github.com/swiftlang/swift/issues/76169)

---

<div class="post-metadata">

**Author:** ![orchetect](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/orchetect/32/5098_2.png) [@orchetect](https://forums.swift.org/u/orchetect)\
**Post date:** [February 28, 2026, 3:04am UTC](https://forums.swift.org/t/typed-throws-do-not-infer-type-in-generic-type-throwing-functions/79036/19 "2026-02-28T03:04:01Z")

</div>

Ran into this issue and though I understand the closure signature requirement, it still feels like a bug.

Case in point, consider the following:

```swift
struct FooError: Error { }

func a(_ block: () throws(FooError) -> Void) { }
func b(_ block: @autoclosure () throws(FooError) -> Void) { }

func c() throws(FooError) { }

a { try b() } // ⚠️ compiler error
a { () throws(FooError) -> Void in try c() } // ✅ works
a { () throws(_) -> Void in try c() } // ✅ works
b(try c()) // ✅ works

```

TL;DR - making the closure an `@autoclosure` produces the desired outcome of the error type being inferred (`func b`). The expectation is that `func a` would have the same inference behavior but it does not, as already discussed.
