# Negated type patterns in \`catch\`

**URL:** <https://forums.swift.org/t/negated-type-patterns-in-catch/90317>\
**Category:** Discussion\
**Tags:** syntax, do-catch, typed-throws\
**Created:** [October 28, 2026, 11:23am UTC](https://forums.swift.org/t/negated-type-patterns-in-catch/90317 "2026-10-28T11:23:23Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![theoriginalbit](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/theoriginalbit/32/12016_2.png) [@theoriginalbit](https://forums.swift.org/u/theoriginalbit)\
**Post date:** [October 28, 2026, 11:23am UTC](https://forums.swift.org/t/negated-type-patterns-in-catch/90317/1 "2026-10-28T11:23:23Z")

</div>

Has anyone else wanted a negated type pattern in `catch`? I couldn't find an earlier thread on this.

Particularly since the introduction of typed-throws ([SE-0413](https://github.com/apple/swift-evolution/blob/main/proposals/0413-typed-throws.md)) I find myself often writing a forwarding clause when a `do` body mixes different typed and untyped throws (or just different typed throws).

```swift
func fn() throws(MyError) {
	do {
		try someTypedThrows() // throws(MyError)
		try someUntypedThrows()
	} catch let error as MyError {
		throw error // making sure it doesn't end up wrapped in .unhandled
	} catch {
		throw .unhandled(error)
	}
}

```

I often feel this would be preferable:

```swift
func fn() throws(MyError) {
	do {
		try someTypedThrows()
		try someUntypedThrows()
	} catch not MyError {
		throw .unhandled(error)
	} // only a `MyError` can escape
}

```

The clause would be non-exhaustive, so anything it doesn't match propagates, and the compiler could narrow the escaping type to `MyError`.

A negated-catch could co-exist with other patterned-catch, but I think it would likely have to be mutually exclusive with a plain-catch as it would only ever see `MyError`, so it’s redundant. I also foresee that the negated-catch would work in a function that does not declare a typed-throws:

```swift
func fn() throws {
	do {
		try someUntypedThrows()
	} catch not MyError {
		throw MyError.unhandled(error)
	} // only a `MyError` can escape
}

```

I wonder then, in the above example, if the compiler would/could infer the throws as `throws(MyError)` instead of `throws(any Error)`?

I'm not set on the spelling. Mirroring the existing `catch is MyError` and `catch let error as MyError` would yield the spellings `catch not MyError` and `catch let error not MyError`; `is not` would read better, but I'm unsure whether requiring two keywords is desirable.

---

<div class="post-metadata">

**Author:** ![FlorianPircher](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/florianpircher/32/39919_2.png) [@FlorianPircher](https://forums.swift.org/u/FlorianPircher)\
**Post date:** [October 28, 2026, 1:02pm UTC](https://forums.swift.org/t/negated-type-patterns-in-catch/90317/2 "2026-10-28T13:02:06Z")

</div>

There is

```swift
do {
	// ...
}
catch let error where !(error is SomeErrorType) {
	// ...
}

```

but that does not provide special support for typed throws.

---

<div class="post-metadata">

**Author:** ![MinerMinerMain](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/minerminermain/32/35300_2.png) [@MinerMinerMain](https://forums.swift.org/u/MinerMinerMain)\
**Post date:** [October 28, 2026, 5:59pm UTC](https://forums.swift.org/t/negated-type-patterns-in-catch/90317/3 "2026-10-28T17:59:33Z")

</div>

> [@theoriginalbit](#):
>
> Mirroring the existing `catch is MyError` and `catch let error as MyError` would yield the spellings `catch not MyError` and `catch let error not MyError`; `is not` would read better, but I'm unsure whether requiring two keywords is desirable.

Having a `not` keyword would very likely not be accepted as it is explicitly barred for Swift Evolution proposals for Boolean values like `is` provides. If you really want these semantics, you might want to seek `~is`/`!is` as a keyword. The keyword `is` only exists in its current contexts as it was distinctly different from the functionality conveyed by `:`\[1\] and is usable in a less restrictive environment.  
It is the best at conveying the information which does not already have a term or symbol of art and pairs with `as` as metatype operators.

Also, as you already stated, you can already express the functionality as you previously mentioned.  
A `do catch` block is effectively a `switch` statement as demonstrated below

```swift
switch Result(catching: {
    try someTypedThrows()
    try someUntypedThrows()
}) {
    case .success: NOP()
    case .failure(let error as MyError): throw error
    case .failure(let error): throw MyError.unhandled(error)
}

```

A `switch` statement must be exhaustive and must explicitly acknowledge all paths. By saying, `catch` unless it is type `MyError` you imply a new catch clause that rethrows. This would impair reasoning in you code as you have to figure out how a particular error is handled and would imply that you can disregard a specific `case` in a `switch` statement which is simply not true.

* * *

1. conformance marker

---

<div class="post-metadata">

**Author:** ![aviva](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aviva/32/44327_2.png) [@aviva](https://forums.swift.org/u/aviva)\
**Post date:** [October 28, 2026, 6:21pm UTC](https://forums.swift.org/t/negated-type-patterns-in-catch/90317/4 "2026-10-28T18:21:15Z")

</div>

I'm not sure if it would be _good_ but it seems like if your error enum can be constructed for arbitrary `Error` types, and the purpose of this syntax is _just_ to rethrow or wrap, the compiler could do that for you and you can just write `try`.

```swift
protocol ConvertableFromError: Error {
    /// Compiler promises to only call this init after attempting to as? cast your error.
    init(wrapping: some Error)
}

```

And the implementation could map to cases for specific known errors...

I'm not sure how much this buys over just using untyped errors. I guess you get exhaustiveness over the cases in `MyError`, which is good, and the ergonomics of automatically wrapping arbitrary errors. And the compiler can do the `as? Self` check for you, potentially more efficiently?

I bet this idea has been floated before.

Also seems like it would bring us closer to implementing `anyhow` / `eyre` esc library in Swift ergonomically, although I think that'd need answers for how to handle passing through untyped throws in generic code.

---

<div class="post-metadata">

**Author:** ![theoriginalbit](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/theoriginalbit/32/12016_2.png) [@theoriginalbit](https://forums.swift.org/u/theoriginalbit)\
**Post date:** [October 30, 2026, 8:25pm UTC](https://forums.swift.org/t/negated-type-patterns-in-catch/90317/5 "2026-10-30T20:25:46Z")

</div>

> [@FlorianPircher](#):
>
> There is
> 
> ```swift
> do {
> // ...
> }
> catch let error where !(error is SomeErrorType) {
> // ...
> }
> 
> ```
> 
> but that does not provide special support for typed throws.

True, there is this and I will admit I do often forget to reach for a where clause on catch specifically.

It is more verbose and I'd say takes more effort to parse at a glance, so I do feel a special case spelling could still add value.

> [@MinerMinerMain](#):
>
> Having a `not` keyword would very likely not be accepted as it is explicitly barred for Swift Evolution proposals for Boolean values like `is` provides. If you really want these semantics, you might want to seek `~is`/`!is` as a keyword.

My understanding is it is explicitly barred for replacements of operators, which this proposal isn't suggesting.

I had considered `!is`/`!is` but felt that Swift didn't have a precedent for a symbol + word as a keyword and may get push back from the complexity it would add to the lexer.

> [@MinerMinerMain](#):
>
> A `do catch` block is effectively a `switch` statement as demonstrated below
> 
> ```swift
> switch Result(catching: {
> try someTypedThrows()
> try someUntypedThrows()
> }) {
> case .success: NOP()
> case .failure(let error as MyError): throw error
> case .failure(let error): throw MyError.unhandled(error)
> }
> 
> ```
> 
> A `switch` statement must be exhaustive and must explicitly acknowledge all paths.

I think I do come back to the same thing I mentioned first up with FlorianPircher, I agree that this works, it's perhaps even more verbose and compared to the where-clause I'd say carries even more cognitive complexity; it's much harder to ascertain at a glance what it's doing, do-catch blocks are better at this.

> [@aviva](#):
>
> I'm not sure if it would be _good_ but it seems like if your error enum can be constructed for arbitrary `Error` types, and the purpose of this syntax is _just_ to rethrow or wrap, the compiler could do that for you and you can just write `try`.

I will admit it was perhaps too contrived of an example, while there are definitely scenarios I have where I'm just wrapping/rethrowing, there's also plenty more where the non-forwarding catch blocks contain business logic before rethrowing (and wrapping if I want to use typed-throws)

---

<div class="post-metadata">

**Author:** ![FlorianPircher](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/florianpircher/32/39919_2.png) [@FlorianPircher](https://forums.swift.org/u/FlorianPircher)\
**Post date:** [October 31, 2026, 12:34pm UTC](https://forums.swift.org/t/negated-type-patterns-in-catch/90317/6 "2026-10-31T12:34:35Z")

</div>

> [@theoriginalbit](#):
>
> > [@FlorianPircher](#):
> >
> > There is
> > 
> > ```swift
> > do {
> > // ...
> > }
> > catch let error where !(error is SomeErrorType) {
> > // ...
> > }
> > 
> > ```
> > 
> > but that does not provide special support for typed throws.
> 
> […]
> 
> It is more verbose and I'd say takes more effort to parse at a glance, so I do feel a special case spelling could still add value.

I just remembered you can shorten it like so:

```swift
catch where !(error is SomeErrorType) {

```

since `error` is the default binding if none is defined explicently.
