# \[Pitch\] \`withTimeout\` method

**URL:** <https://forums.swift.org/t/pitch-withtimeout-method/84447>\
**Category:** Swift Async Algorithms\
**Tags:** asyncawait, async-algorithms\
**Created:** [January 29, 2026, 10:11am UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447 "2026-01-29T10:11:23Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![FranzBusch](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/franzbusch/32/19447_2.png) [@FranzBusch](https://forums.swift.org/u/FranzBusch)\
**Post date:** [January 29, 2026, 10:11am UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/1 "2026-01-29T10:11:23Z")

</div>

Hey everyone,

I have drafted up a pitch proposal for `swift-async-algorithms` to introduce a new `withTimeout` method.

You can find the whole pitch [here](https://github.com/apple/swift-async-algorithms/pull/396)

## Introduction

This proposal introduces `withTimeout`, a function that executes an asynchronous operation with a specified time limit. If the operation completes before the timeout expires, the function returns the result; if the timeout expires first, the operation is cancelled and a `TimeoutError` is thrown once the operation completed.

## Motivation

Asynchronous operations in Swift can run indefinitely, which creates several problems in real-world applications:

1. Network operations may hang when servers become unresponsive, consuming resources and degrading user experience.
2. Server-side applications need predictable request handling times to maintain service level agreements and prevent resource exhaustion.
3. Batch processing requires mechanisms to prevent individual tasks from blocking entire workflows.
4. Resource management becomes difficult when operations lack time bounds, leading to connection pool exhaustion and memory leaks.

Currently, developers must implement timeout logic manually using task groups and clock sleep operations, resulting in verbose, error-prone code that's difficult to compose with surrounding async contexts. Each implementation must carefully handle cancellation, error propagation, and race conditions between the operation and timer.

## Proposed solution

This proposal introduces `withTimeout`, a function that executes an asynchronous operation with a time limit. The solution provides a clean, composable API that handles cancellation and error propagation automatically:

```swift
do {
    let result = try await withTimeout(in: .seconds(5)) {
        try await fetchDataFromServer()
    }
    print("Data received: \(result)")
} catch let error as TimeoutError<NetworkError> {
    print("Request timed out: \(error.underlying)")
}

```

The solution is safer than manual implementations because it handles all race conditions between the operation and timeout timer, ensures proper cleanup through structured concurrency, and provides clear semantics for cancellation behavior.

## Detailed design

#### TimeoutError

```swift
/// An error that wraps an underlying error when an operation times out.
public struct TimeoutError<UnderylingError: Error>: Error {
  /// The error thrown by the timed-out operation.
  public var underlying: UnderylingError

  /// Creates a timeout error with the specified underlying error.
  ///
  /// - Parameter underlying: The error thrown by the operation that timed out.
  public init(underlying: UnderylingError) {
    self.underlying = underlying
  }
}

```

`TimeoutError` wraps the original error type thrown by the timed-out operation, preserving type information for error handling. This allows callers to access the underlying error while clearly indicating that a timeout occurred.

#### withTimeout Function

````swift
/// Executes an asynchronous operation with a specified timeout duration.
///
/// Use this function to limit the execution time of an asynchronous operation. If the operation
/// completes before the timeout expires, this function returns the result. If the timeout expires
/// first, this function cancels the operation and throws a ``TimeoutError``.
///
/// The following example demonstrates using a timeout to limit a network request:
///
/// ```swift
/// do {
/// let result = try await withTimeout(in: .seconds(5)) {
/// try await fetchDataFromServer()
/// }
/// print("Data received: \(result)")
/// } catch let error as TimeoutError<NetworkError> {
/// print("Request timed out: \(error.underlying)")
/// }
/// ```
///
/// - Important: This function cancels the operation when the timeout expires, but waits for the operation
/// to return. The function may run longer than the specified timeout duration if the operation doesn't respond
/// to cancellation immediately.
///
/// - Parameters:
/// - timeout: The maximum duration to wait for the operation to complete.
/// - tolerance: The tolerance used for the sleep.
/// - clock: The clock to use for measuring time. The default is `ContinuousClock()`.
/// - body: The asynchronous operation to execute within the timeout period.
///
/// - Returns: The result of the operation if it completes before the timeout expires.
///
/// - Throws: A ``TimeoutError`` containing the underlying error if the operation throws or times out.
nonisolated(nonsending) public func withTimeout<Return, Failure: Error, Clock: _Concurrency.Clock>(
  in timeout: Clock.Instant.Duration,
  tolerance: Clock.Instant.Duration? = nil,
  clock: Clock = .continuous,
  body: nonisolated(nonsending) () async throws(Failure) -> Return
) async throws(TimeoutError<Failure>) -> Return {

````

#### Non-escaping nonisolated(nonsending) operation closure

Many existing `withTimeout` implementations require a `@Sendable` and `@escaping` closure which makes it hard to compose in isolated context and use non-Sendable types. This design ensures that the closure is both non-escaping and nonisolated(nonsending) for composability:

```swift
actor DataProcessor {
    var cache: [String: Data] = [:]
    
    func fetchWithTimeout(url: String) async throws {
        // The closure can access actor-isolated state because it's nonisolated(nonsending)
        let data = try await withTimeout(in: .seconds(5)) {
            if let cached = cache[url] {
                return cached
            }
            return try await URLSession.shared.data(from: URL(string: url)!)
        }
        cache[url] = data
    }
}

```

If the closure were `@Sendable`, it couldn't access actor-isolated state like `cache`. The `nonisolated(nonsending)` annotation allows the closure to compose with surrounding code regardless of isolation context, while maintaining safety guarantees.

### Implementation Details

The implementation uses structured concurrency with task groups to race the operation against a timeout timer:

1. Two tasks are created: one executes the operation, the other sleeps for the timeout duration
2. The first task to complete determines the result
3. When either task completes, `cancelAll()` cancels the other task
4. If the timeout expires first, the operation is cancelled but the function waits for it to return
5. The function handles both the operation's result and any errors thrown

**Important behavioral note:** The function cancels the operation when the timeout expires, but waits for the operation to return. This means `withTimeout` may run longer than the specified timeout duration if the operation doesn't respond to cancellation immediately. This design ensures proper cleanup and prevents resource leaks from abandoned tasks.

## Effect on API resilience

This is an additive API and no existing systems are changed, however it will introduce a few new types that will need to be maintained as ABI interfaces.

## Alternatives considered

### @Sendable and @escaping Closure

An earlier design considered using `@Sendable` and `@escaping` for the closure parameter:

```swift
public func withTimeout<Return: Sendable, Failure: Error, Clock: _Concurrency.Clock>(
  in timeout: Clock.Duration,
  clock: Clock = ContinuousClock(),
  body: @Sendable @escaping () async throws(Failure) -> Return
) async throws(TimeoutError<Failure>) -> Return

```

Looking forward to feedback and questions!

Franz

---

<div class="post-metadata">

**Author:** ![Honza\_Dvorsky](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/honza_dvorsky/32/29867_2.png) [@Honza\_Dvorsky](https://forums.swift.org/u/Honza_Dvorsky)\
**Post date:** [January 29, 2026, 10:52am UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/2 "2026-01-29T10:52:12Z")

</div>

A big +1, I've had to copy-paste a similar implementation in too many projects at this point.

One possible enhancement: can we add a `withDeadline` flavor, and `withTimeout` can just call through to `withDeadline`? Sometimes you have the deadline time instance rather than the duration, so it'd be good not to have to do the calculation and risk unpredictable drift.

---

<div class="post-metadata">

**Author:** ![OneSadCookie](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/onesadcookie/32/3205_2.png) [@OneSadCookie](https://forums.swift.org/u/OneSadCookie)\
**Post date:** [January 29, 2026, 11:04am UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/3 "2026-01-29T11:04:17Z")

</div>

I think this is a good idea, everyone ends up needing this at some point, and it's nice to have it carefully done in a commonly-used package.

The caveat that just about everyone _misses_ when they first see this kind of function, is that if the `body` _doesn't_ respond promptly to cancellation, `withTimeout` doesn't return promptly after the desired duration. _This is correct_, and _necessary_, but not intuitive to most people.

Particular cases where it can be dangerous are ObjC completionHandler methods that've been imported as async, and situations where people have used `withCheckedContinuation` without `withTaskCancellationHandler`.

---

<div class="post-metadata">

**Author:** ![FranzBusch](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/franzbusch/32/19447_2.png) [@FranzBusch](https://forums.swift.org/u/FranzBusch)\
**Post date:** [January 29, 2026, 11:08am UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/4 "2026-01-29T11:08:27Z")

</div>

> [@Honza\_Dvorsky](#):
>
> One possible enhancement: can we add a `withDeadline` flavor, and `withTimeout` can just call through to `withDeadline`? Sometimes you have the deadline time instance rather than the duration, so it'd be good not to have to do the calculation and risk unpredictable drift.

I think that makes total sense and adding a `withDeadline` method that takes an `Clock.Instant` instead of a `Clock.Instant.Duration` is easy to add.

> [@OneSadCookie](#):
>
> The caveat that just about everyone _misses_ when they first see this kind of function, is that if the `body` _doesn't_ respond promptly to cancellation, `withTimeout` doesn't return promptly after the desired duration. _This is correct_, and _necessary_, but not intuitive to most people.

Yes, that's right. This is due to how structured concurrency works and that there is no way to "force" async code to return right away. It needs to run until its natural end. I tried to call this out in the docs of the method explicitly:

```swift
/// - Important: This function cancels the operation when the timeout expires, but waits for the operation
/// to return. The function may run longer than the specified timeout duration if the operation doesn't respond
/// to cancellation immediately.

```

---

<div class="post-metadata">

**Author:** ![swhitty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/swhitty/32/10082_2.png) [@swhitty](https://forums.swift.org/u/swhitty)\
**Post date:** [January 29, 2026, 11:32am UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/5 "2026-01-29T11:32:13Z")

</div>

This is really nice — nonsending & nonescaping make this API a pleasure to use

---

<div class="post-metadata">

**Author:** ![ph1ps](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ph1ps/32/35459_2.png) [@ph1ps](https://forums.swift.org/u/ph1ps)\
**Post date:** [January 29, 2026, 11:36am UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/6 "2026-01-29T11:36:04Z")

</div>

First of all, love to see this pitched. Having this at a more central and official place is something I appreciate and I will be able to sunset my version of this algorithm. I added some comments in the PR, although I think my second comment I will repeat here:

* * *

I think the `Duration` variant of `withTimeout` could take `any Clock<Duration>` rather than some clock.

Imagine this model:

```swift
class Model {

  func doSomething() async throws {
    try await withTimeout(in: .seconds(5)) { ... }
  }
}

```

If you were to unit test `doSomething`, you would normally try to inject a custom clock, to not make the unit test wait for 5 seconds.

Either with some sort of dependency injection, or with simply passing it along the initializer you could do this:

```swift
class Model {

  let clock: any Clock<Duration>

  func doSomething() async throws {
    try await withTimeout(in: .seconds(5), clock: clock) { ... }
  }
}

```

At call site:

```swift
let model1 = Model(clock: ContinuousClock())
let model2 = Model(clock: TestClock())

```

When using some clock, you would have to make Model generic over the clock used for timeouts, which is inconvenient. Kind of the same motivation as in [SE-0374](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0374-clock-sleep-for.md).

* * *

The implementation assumes a clock only ever throws when cancelled, is this okay to assume so? I previously had my implementation explicitly not as typed throws because of that.

* * *

> [@Honza\_Dvorsky](#):
>
> One possible enhancement: can we add a `withDeadline` flavor, and `withTimeout` can just call through to `withDeadline`? Sometimes you have the deadline time instance rather than the duration, so it'd be good not to have to do the calculation and risk unpredictable drift.

+1

---

<div class="post-metadata">

**Author:** ![swhitty](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/swhitty/32/10082_2.png) [@swhitty](https://forums.swift.org/u/swhitty)\
**Post date:** [January 29, 2026, 11:42am UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/7 "2026-01-29T11:42:51Z")

</div>

I have referred to these as timeouts and used `withThrowingTimeout` for my implementations but another possibility is using `withCancellation` to express that the task running the closure is cancelled and the regular cooperative cancellation rules apply.

---

<div class="post-metadata">

**Author:** ![FranzBusch](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/franzbusch/32/19447_2.png) [@FranzBusch](https://forums.swift.org/u/FranzBusch)\
**Post date:** [January 29, 2026, 11:52am UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/8 "2026-01-29T11:52:13Z")

</div>

> [@ph1ps](#):
>
> I think the `Duration` variant of `withTimeout` could take `any Clock<Duration>` rather than some clock.

I replied in the PR to this but adding here as well. I don't think taking `any Clock<Duration>` is necessary to make your dependency injection work. You can do this already by opening the existential by passing the `any Clock<Duration>` to a `some Clock<Duration>` like this:

```swift
@Test(arguments: [ContinuousClock()])
func dependencyInjection(clock: any Clock<Duration>) async throws {
  try await self.concreteClock(clock: clock)
}

private func concreteClock(clock: some Clock<Duration>) async throws {
  try await withTimeout(
    in: .seconds(10),
    clock: clock
  ) {
    try await Task.sleep(for: .milliseconds(10))
  }
}

```

> [@ph1ps](#):
>
> The implementation assumes a clock only ever throws when cancelled, is this okay to assume so? I previously had my implementation explicitly not as typed throws because of that (same goes for my [retry pitch](https://forums.swift.org/t/pitch-retry-backoff/82483)).

It's a fair question. Right now I think every clock implementation adheres to this but nothing forces it. Sadly, we can't change the `Clock` protocol without breaking ABI AFAIK.

---

<div class="post-metadata">

**Author:** ![ph1ps](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ph1ps/32/35459_2.png) [@ph1ps](https://forums.swift.org/u/ph1ps)\
**Post date:** [January 29, 2026, 11:54am UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/9 "2026-01-29T11:54:24Z")

</div>

> [@FranzBusch](#):
>
> I replied in the PR to this but adding here as well

Sorry about the noise.

> [@FranzBusch](#):
>
> I don't think taking `any Clock<Duration>` is necessary to make your dependency injection work. You can do this already by opening the existential by passing the `any Clock<Duration>` to a `some Clock<Duration>` like this:

Ah, forgot this works. Thanks.

---

<div class="post-metadata">

**Author:** ![johannesweiss](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/johannesweiss/32/38183_2.png) [@johannesweiss](https://forums.swift.org/u/johannesweiss)\
**Post date:** [January 29, 2026, 12:41pm UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/10 "2026-01-29T12:41:11Z")

</div>

Obvious +1 and yes please for me. I've got one of those in every single project I've ever done with Swift Concurrency.

---

<div class="post-metadata">

**Author:** ![sliemeobn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/sliemeobn/32/27698_2.png) [@sliemeobn](https://forums.swift.org/u/sliemeobn)\
**Post date:** [January 29, 2026, 12:58pm UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/11 "2026-01-29T12:58:53Z")

</div>

looks very good overall, a very welcome addition!

@FranzBusch  
Could you explain a bit how the various combinations of errors/returns are expressed?

I guess it can be:

- returns, no timeout
- returns, but canceled by timeout
- throws, no timeout
- throws, canceled by timeout

> [@FranzBusch](#):
>
> This allows callers to access the underlying error while clearly indicating that a timeout occurred.

Does it indicate this? How would "just threw and error" look like?

---

<div class="post-metadata">

**Author:** ![FranzBusch](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/franzbusch/32/19447_2.png) [@FranzBusch](https://forums.swift.org/u/FranzBusch)\
**Post date:** [January 29, 2026, 1:24pm UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/12 "2026-01-29T13:24:00Z")

</div>

> [@sliemeobn](#):
>
> Does it indicate this? How would "just threw and error" look like?

I think I see what you are getting at. The method right now always throws a `TimeoutError` even in the case when no timeout occurred and the operation just threw. I think `TimeoutError` needs a slight adjustment so that it indicates what threw the error, something like this:

```swift
enum TimeoutError<OperationError: Error>: Error {
  case timedOut(OperationError)
  case operationFailed(OperationError)
}

```

Which would mean the method behaves like this:

1. (no-timeout, operation returns X) -\> return X
2. (no-timeout, operation throws E) -\> throw TimeoutError.operationFailed(E)
3. (timeout cancels operation, operation returns X) -\> return X
4. (timeout cancels operation, operation throws E) -\> throw TimeoutError.timedOut(E)

---

<div class="post-metadata">

**Author:** ![bbrk24](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/bbrk24/32/27370_2.png) [@bbrk24](https://forums.swift.org/u/bbrk24)\
**Post date:** [January 29, 2026, 1:58pm UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/13 "2026-01-29T13:58:26Z")

</div>

> [@FranzBusch](#):
>
> Which would mean the method behaves like this:
> 
> 1. (no-timeout, operation returns X) -\> return X
> 2. (no-timeout, operation throws E) -\> throw TimeoutError.operationFailed(E)
> 3. (timeout cancels operation, operation returns X) -\> return X
> 4. (timeout cancels operation, operation throws E) -\> throw TimeoutError.timedOut(E)

So is there no way to know whether the operation timed out if the callback provided isn't throwing?

---

<div class="post-metadata">

**Author:** ![FranzBusch](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/franzbusch/32/19447_2.png) [@FranzBusch](https://forums.swift.org/u/FranzBusch)\
**Post date:** [January 29, 2026, 2:10pm UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/14 "2026-01-29T14:10:53Z")

</div>

> [@bbrk24](#):
>
> So is there no way to know whether the operation timed out if the callback provided isn't throwing?

Correct. This proposal treats an operation that returns successfully always as successful, even in the case where it returned after the timeout triggered. In my opinion, this is the only right thing to do since we can't generically say much about the return value itself. It might be that the operation noticed the cancellation, saved off the state, and returned a partial successful state. Generally speaking, I think almost any async method should also be throwing, especially if that method wants to indicate that it exited early due to cancellation.

---

<div class="post-metadata">

**Author:** ![allevato](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/allevato/32/385_2.png) [@allevato](https://forums.swift.org/u/allevato)\
**Post date:** [January 29, 2026, 2:21pm UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/15 "2026-01-29T14:21:24Z")

</div>

People who have read my posts in the past know me as the person who says "not everything needs to go in the standard library, we should take advantage of Swift's rich package ecosystem."

...so here I am doing a 180. I'm curious, why is this being pitched for inclusion in swift-async-algorithms instead of the `_Concurrency` module? At a glance, most of the APIs in swift-async-algorithms deal with sequences and values at a higher level, whereas this feels like one of those small-but-impactful fundamental building blocks that deserves inclusion in the standard library. But I suppose the counterargument to that would be that this can _already_ be built with the fundamental building blocks in `_Concurrency`; i.e., it requires no new APIs that talk to the runtime?

Either way, I think it's a great addition, but I'm interested in the general thought process of what goes where.

---

<div class="post-metadata">

**Author:** ![FranzBusch](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/franzbusch/32/19447_2.png) [@FranzBusch](https://forums.swift.org/u/FranzBusch)\
**Post date:** [January 29, 2026, 2:29pm UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/16 "2026-01-29T14:29:54Z")

</div>

> [@allevato](#):
>
> ...so here I am doing a 180. I'm curious, why is this being pitched for inclusion in swift-async-algorithms instead of the `_Concurrency` module? At a glance, most of the APIs in swift-async-algorithms deal with sequences and values at a higher level, whereas this feels like one of those small-but-impactful fundamental building blocks that deserves inclusion in the standard library. But I suppose the counterargument to that would be that this can _already_ be built with the fundamental building blocks in `_Concurrency`; i.e., it requires no new APIs that talk to the runtime?

It's a good question. My motivation for pitching this to `swift-async-algorithms` is twofold:

1. It makes it available more broadly since it isn't tied to a specific Swift version or platform availability.
2. While it is possible to implement this entirely with a public API, an implementation inside the `_Concurrency` module might want to tie this even closer with executors to make this even more performant. Such an implementation is more complex, and there are many open questions how that would work exactly. I think, however, we shouldn't hold back the entire ecosystem with having a perfect solution in the `_Concurrency` module and instead providing something in the package ecosystem until then. Similar to how `swift-collections` provides useful data structures outside the stdlib.

Whether `swift-async-algorithms` should contain more than just algorithms outside of `AsyncSequence`s is a good question. In my personal opinion, yes, because nothing in the package name indicates a connection to `AsyncSequence`, and additional packages always bring an additional maintenance overhead. That's just my opinion though and @Philippe_Hausler most likely has thoughts on this as well.

---

<div class="post-metadata">

**Author:** ![Philippe\_Hausler](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/philippe_hausler/32/22569_2.png) [@Philippe\_Hausler](https://forums.swift.org/u/Philippe_Hausler)\
**Post date:** [January 29, 2026, 5:17pm UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/17 "2026-01-29T17:17:24Z")

</div>

> [@FranzBusch](#):
>
> ecause nothing in the package name indicates a connection to `AsyncSequence`, and additional packages always bring an additional maintenance overhead.

So the algorithms housed there are not per-se strictly relegated to _just_ async sequence; the original intent was to introduce things like this type of algorithm here (hence the name). However the catch is that most of the non-async-sequence APIs that would be introduced need runtime level support.

Also there is the question of: is any of the proposed concepts possibly belonging in `_Concurrency` itself? e.g. should you be required to type out `import` to use it?

To the pitch itself: timeouts are inherently non-composable. Consider for example a HTTP request - how does one compose the timeout for a dns resolution (which rightfully should be async and have a temporal concept of failure) and the temporal concept of failure for writing out data, and the temporal concept of getting a complete message back? Instead the composable version is for a deadline to be passed instead - this permits an instant to be passed when the whole thing is due by. Sub items that participate in the temporal concept of failure can choose to a) use the deadline as is, b) minimum with some other value they have, c) not participate. The key option there is the determinate of a minimum. @ktoso likely has deeper thoughts on this since we have spoken about this at length and I am just paraphrasing his logic (which I found quite compelling in the past).

The other nicety of deadlines is that you can not only make references to Douglass Adams, but they could interact at a task-local level but also have shorthand to expose as a timeout that creates a deadline. So all in all I would not be in favor of timeouts but strongly in favor of deadlines.

---

<div class="post-metadata">

**Author:** ![NotTheNHK](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/notthenhk/32/43199_2.png) [@NotTheNHK](https://forums.swift.org/u/NotTheNHK)\
**Post date:** [January 29, 2026, 6:09pm UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/18 "2026-01-29T18:09:40Z")

</div>

> [@OneSadCookie](#):
>
> The caveat that just about everyone _misses_ when they first see this kind of function, is that if the `body` _doesn't_ respond promptly to cancellation, `withTimeout` doesn't return promptly after the desired duration. _This is correct_, and _necessary_, but not intuitive to most people.

Swift concurrency is fundamentally cooperative, and if this is not intuitive, then we failed to establish that fact. However, I think in this case we do a [good job](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency/#Task-Cancellation) of making this clear.

+1 for @Philippe_Hausler’s idea of a deadline approach instead. I think timeouts don’t fit very well into Swift’s concurrency model.

---

<div class="post-metadata">

**Author:** ![Joseph\_Heck](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joseph_heck/32/22369_2.png) [@Joseph\_Heck](https://forums.swift.org/u/Joseph_Heck)\
**Post date:** [January 29, 2026, 6:20pm UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/19 "2026-01-29T18:20:31Z")

</div>

I was wondering the exact same thing - how to differentiate a timeout error from an underlying thrown error from whatever processing I was doing. Huge +1 to this whole concept, and yes please for the adjustment to the TimeoutError to allow it to be differentiated on need.

---

<div class="post-metadata">

**Author:** ![Philippe\_Hausler](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/philippe_hausler/32/22569_2.png) [@Philippe\_Hausler](https://forums.swift.org/u/Philippe_Hausler)\
**Post date:** [January 29, 2026, 6:27pm UTC](https://forums.swift.org/t/pitch-withtimeout-method/84447/20 "2026-01-29T18:27:19Z")

</div>

Another commonly needed thing that we should consider is making the `TimeoutError` generic upon the clock and carry the deadline so that folks can extract the information around the given deadline when a failure occurs.

[Next page](https://forums.swift.org/t/pitch-withtimeout-method/84447.md?page=2)
