<!--
{
  "availability" : [
    "iOS: 17.0.0 -",
    "iPadOS: 17.0.0 -",
    "macCatalyst: 17.0.0 -",
    "macOS: 14.0.0 -",
    "tvOS: 17.0.0 -",
    "visionOS: 1.0.0 -",
    "watchOS: 10.0.0 -"
  ],
  "documentType" : "symbol",
  "framework" : "Swift",
  "identifier" : "/documentation/Swift/withThrowingDiscardingTaskGroup(returning:isolation:body:)",
  "metadataVersion" : "0.1.0",
  "role" : "Function",
  "symbol" : {
    "kind" : "Function",
    "modules" : [
      "Swift"
    ],
    "preciseIdentifier" : "s:12_Concurrency31withThrowingDiscardingTaskGroup9returning9isolation4bodyxxm_ScA_pSgYixAA0cdeF0Vys5Error_pGzYaKXEtYaKlF"
  },
  "title" : "withThrowingDiscardingTaskGroup(returning:isolation:body:)"
}
-->

# withThrowingDiscardingTaskGroup(returning:isolation:body:)

Starts a new scope that can contain a dynamic number of child tasks.

```
@backDeployed(before: macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0)
func withThrowingDiscardingTaskGroup<GroupResult>(returning returnType: GroupResult.Type = GroupResult.self, isolation: isolated (any Actor)? = #isolation, body: (inout ThrowingDiscardingTaskGroup<any Error>) async throws -> GroupResult) async throws -> GroupResult
```

## Discussion

Unlike a [`ThrowingTaskGroup`](/documentation/Swift/ThrowingTaskGroup), the child tasks as well as their results are
discarded as soon as the tasks complete. This prevents the discarding
task group from accumulating many results waiting to be consumed, and is
best applied in situations where the result of a child task is some form
of side-effect.

A group *always* waits for all of its child tasks
to complete before it returns. Even canceled tasks must run until
completion before this function returns.
Canceled child tasks cooperatively react to cancellation and attempt
to return as early as possible.
After this function returns, the task group is always empty.

It is not possible to explicitly await completion of child-tasks,
however the group will automatically await *all* child task completions
before returning from this function:

```
try await withThrowingDiscardingTaskGroup { group in
  group.addTask { /* slow-task */ }
  // slow-task executes...
}
// guaranteed that slow-task has completed and the group is empty & destroyed
```

Refer to [`TaskGroup`](/documentation/Swift/TaskGroup) documentation for detailed discussion of semantics shared between all task groups.

# Task Group Cancellation

You can cancel a task group and all of its child tasks
by calling the [`cancelAll()`](/documentation/Swift/TaskGroup/cancelAll()) method on the task group,
or by canceling the task in which the group is running.

If you call `addTask(priority:operation:)` to create a new task in a canceled group,
that task is immediately canceled after creation.
Alternatively, you can call `asyncUnlessCancelled(priority:operation:)`,
which doesn’t create the task if the group has already been canceled.
Choosing between these two functions
lets you control how to react to cancellation within a group:
some child tasks need to run regardless of cancellation,
but other tasks are better not even being created
when you know they can’t produce useful results.

# Error Handling and Implicit Cancellation

Since it is not possible to explicitly await individual task completions,
it is also not possible to “re-throw” an error thrown by one of the child
tasks using the same pattern as one would in a [`ThrowingTaskGroup`](/documentation/Swift/ThrowingTaskGroup):

```
// ThrowingTaskGroup, pattern not applicable to ThrowingDiscardingTaskGroup
try await withThrowingTaskGroup(of: Void.self) { group in
  group.addTask { try boom() }
  try await group.next() // re-throws "boom"
}
```

Since discarding task groups don’t have access to `next()`, this pattern
cannot be used.
Instead,
a *throwing discarding task group implicitly cancels itself whenever any
of its child tasks throws*.

The *first error* thrown inside such task group
is then retained and thrown
out of the `withThrowingDiscardingTaskGroup` method when it returns.

```
try await withThrowingDiscardingTaskGroup { group in
  group.addTask { try boom(1) }
  group.addTask { try boom(2, after: .seconds(5)) }
  group.addTask { try boom(3, after: .seconds(5)) }
}
```

Generally, this suits the typical use cases of a
discarding task group well, however, if you want to prevent specific
errors from canceling the group you can catch them inside the child
task’s body like this:

```
try await withThrowingDiscardingTaskGroup { group in
  group.addTask {
    do {
      try boom(1)
    } catch is HarmlessError {
      return
    }
  }
  group.addTask {
    try boom(2, after: .seconds(5))
  }
}
```

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)