Skip to content

fix: Try.Run must not throw on whitespace exception message (#273) - #276

Merged
Chris-Wolfgang merged 1 commit into
vNextfrom
tier2/273-whitespace-message-fix
Jul 17, 2026
Merged

fix: Try.Run must not throw on whitespace exception message (#273)#276
Chris-Wolfgang merged 1 commit into
vNextfrom
tier2/273-whitespace-message-fix

Conversation

@Chris-Wolfgang

Copy link
Copy Markdown
Owner

Closes #273.

Bug

Try.Run* catches every Exception and passes ex.Message straight to Result.Failure. Result.Failure rejects null / empty / whitespace with ArgumentException — so Try.Run(() => throw new X(" ")) throws ArgumentException from inside its own catch instead of returning Failed. Defeats the whole point of the wrapper.

Fix

Private SafeErrorMessage(Exception) helper coerces null / empty / whitespace ex.Message to ex.GetType().Name. Every catch block (Run(Action), Run<T>, RunAsync(Action), RunAsync<T>) routes through it.

Regression tests

TryRunWhitespaceMessageTests.cs covers:

  • "", " ", "\t", "\n" on every overload → returns Failed, ErrorMessage == nameof(InvalidOperationException)
  • Non-whitespace message → preserved verbatim (guard against over-correction)

Discovery

FsCheck property Fuzz_Try_Run_of_throwing_action_carries_message in PR #274 falsified this on iteration 19. Filed as #273, tightened the property with a whitespace-skip guard so #274 could ship clean; this PR is the real fix. Once both land, a follow-up removes the skip so the fuzz exercises the whole message space.

Stacked-PR base

Base = vNext.

Local run

dotnet test -c Release -f net10.0102/102 pass (11 new whitespace-regression tests + the existing 91). Zero warnings.

Test plan

Closes #273.

`Try.Run*` was catching every Exception and passing `ex.Message`
straight to `Result.Failure`. `Result.Failure` rejects
null / empty / whitespace strings with ArgumentException — meaning
`Try.Run(() => throw new X(" "))` threw ArgumentException from
inside its own catch instead of returning a Failed Result. Defeats
the entire point of the wrapper for any exception whose Message
happens to be whitespace-only (or one thrown with the
parameterless framework ctor, whose default message is culture-
dependent and can be empty).

Fix: private `SafeErrorMessage(Exception)` helper coerces a
null / empty / whitespace `ex.Message` to `ex.GetType().Name`
before handing it to `Result.Failure`. All four catch blocks
(Run, Run<T>, RunAsync, RunAsync<T>) route through it.

Regression tests in `TryRunWhitespaceMessageTests.cs` cover both
the whitespace-coerce-to-type-name path and the real-message
preservation path across every overload.

Discovered by the FsCheck fuzz property added in PR #274. Once
this ships and #274 lands, the `string.IsNullOrWhiteSpace` skip in
that PR's Fuzz_Try_Run_of_throwing_action_carries_message +
Try_Run_of_throwing_action_carries_message_round_trip properties
can be removed as a follow-up so the fuzz exercises the whole
space including whitespace inputs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 16, 2026 02:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.

2 participants