Skip to content

Parameterless OrInner<T>() no longer discards its inner-exception match (GH-3766) - #3769

Merged
jeremydmiller merged 1 commit into
mainfrom
gh-3766/orinner-parameterless-match
Aug 1, 2026
Merged

Parameterless OrInner<T>() no longer discards its inner-exception match (GH-3766)#3769
jeremydmiller merged 1 commit into
mainfrom
gh-3766/orinner-parameterless-match

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Summary

Fixes #3766 — the parameterless PolicyExpression.OrInner<TException>() built the combined exception match and then discarded it (_match was never reassigned), so the inner-exception match silently never applied. The predicate overload directly below it was already correct.

One subtlety worth noting: ExceptionMatchExtensions.Or mutates in place when the receiver is already an OrMatch, so the parameterless overload accidentally worked when chained after another .Or() — but in the common OnException<T>().OrInner<T>() shape, _match is a TypeMatch and the new OrMatch was thrown away.

Impact

As reported: OnException<NpgsqlException>().OrInner<NpgsqlException>().RetryWithCooldown(...) never matched MartenCommandException wrapping an NpgsqlException, so messages failing during a brief Postgres outage skipped the retry ladder and dead-lettered on the first attempt.

Testing

The existing or_predicate_on_inner_type test already exercised the buggy path but was missing the assertion on the wrapped-exception call — the continuation was computed and dropped on the floor, which is how this survived. Both it and its predicate twin now assert DiscardEnvelope for wrapped inner exceptions. Verified red without the product fix, green with it.

🤖 Generated with Claude Code

https://claude.ai/code/session_013eR4GL278688VhyhrGcttJ

…ch (GH-3766)

The parameterless PolicyExpression.OrInner<TException>() built the combined
match but never assigned it back to _match, so the inner-exception match
silently never applied unless _match already happened to be an OrMatch.
Policies like OnException<NpgsqlException>().OrInner<NpgsqlException>()
matched only the outer exception type, sending wrapped failures straight
to the dead letter queue on first attempt.

The existing or_predicate_on_inner_type test called
DetermineExecutionContinuation for the wrapped case but was missing its
assertion, which is how this survived — both it and the predicate twin
now assert DiscardEnvelope for wrapped inner exceptions.

Closes GH-3766

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013eR4GL278688VhyhrGcttJ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parameterless OrInner<T>() silently discards its match — policy never applies to wrapped exceptions

1 participant