Skip to content

Add TaskResult.ofCatchTask - #353

Merged
TheAngryByrd merged 4 commits into
masterfrom
copilot/add-ofcatchtask-to-taskresult
Feb 25, 2026
Merged

TheAngryByrd merged 4 commits into
masterfrom
copilot/add-ofcatchtask-to-taskresult

Conversation

Copilot AI commented Feb 25, 2026 •

Copy link
Copy Markdown
Contributor
  • Explore codebase and understand existing patterns
  • Add TaskResult.ofCatchTask function to TaskResult.fs with doc comments
  • Add doc comment to TaskResult.ofTask clarifying it doesn't catch exceptions (with reference to ofCatchTask)
  • Add tests for TaskResult.ofCatchTask in tests/FsToolkit.ErrorHandling.Tests/TaskResult.fs
  • Add gitbook/taskResult/ofCatchTask.md documentation
  • Update gitbook/taskResult/ofTask.md to reference ofCatchTask and show error case properly (exception propagates)
  • Update gitbook/SUMMARY.md to include ofCatchTask
  • Fix incorrect return failwith syntax in ofCatchTask doc comment example (both in source and gitbook)
  • Fix ofTask.md Example 2 to show that exceptions propagate (not caught)
  • Validate with ./build.sh CheckFormatCode — passes
Original prompt

This section details on the original issue you should resolve

<issue_title>TaskResult.ofTask</issue_title>
<issue_description>Is your feature request related to a problem? Please describe.
It is confusing that we can turn task into taskresult<'T,exn> but if task throws we would not receive exn, but got escaped

Describe the solution you'd like
I define this in my projects to wrap around throwable tasks

module TaskResult =
    let ofCatchTask<'T> (item: Task<'T>) =
        taskResult {
            let! result = item |> Task.catch
            return! result |> Result.ofChoice
        }

Additional context
Unsure if not too simple, but i think this would be nice addition to TaskResult.ofTask (which actually catches -> turns into Result correctly)</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: TheAngryByrd <1490044+TheAngryByrd@users.noreply.github.com>
Copilot AI changed the title [WIP] Add ofCatchTask function to TaskResult module Add TaskResult.ofCatchTask Feb 25, 2026
Copilot AI requested a review from TheAngryByrd February 25, 2026 02:54
@TheAngryByrd
TheAngryByrd requested a review from Copilot February 25, 2026 03:05
@TheAngryByrd
TheAngryByrd marked this pull request as ready for review February 25, 2026 03:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR adds TaskResult.ofCatchTask to handle the common pattern of lifting a throwable Task<'T> into Task<Result<'T, exn>> by catching exceptions and mapping them to the Error case. This addresses a gap where the existing TaskResult.ofTask wraps values in Ok without catching exceptions, leading to unexpected exception propagation.

Changes:

  • Add ofCatchTask function that catches task exceptions and maps them to Error, similar to how AsyncResult.ofTask works
  • Update ofTask documentation to clarify it doesn't catch exceptions and cross-reference the new function
  • Add comprehensive tests covering success and exception scenarios
  • Add complete documentation with examples and function signatures

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/FsToolkit.ErrorHandling/TaskResult.fs Adds ofCatchTask implementation using Task.catch |> Task.map Result.ofChoice pattern; adds XML documentation to ofTask clarifying exception behavior
tests/FsToolkit.ErrorHandling.Tests/TaskResult.fs Adds two test cases: one verifying successful tasks return Ok, another verifying throwing tasks return Error with captured exception
gitbook/taskResult/ofTask.md Adds note clarifying ofTask does not catch exceptions and links to ofCatchTask
gitbook/taskResult/ofCatchTask.md New documentation page describing the function with signature and examples
gitbook/SUMMARY.md Adds link to ofCatchTask documentation in alphabetical order under Transforms section

Comment thread gitbook/taskResult/ofCatchTask.md Outdated
Comment thread gitbook/taskResult/ofTask.md Outdated
@@ -25,3 +27,4 @@ let result = TaskResult.ofTask (task { return 42 })
let result = TaskResult.ofTask (task { return System.Exception("error") })
// task { return Error (System.Exception("error")) }

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

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

This example is incorrect. Since ofTask does not catch exceptions and just wraps the value in Ok, returning a System.Exception value would result in Ok(System.Exception("error")), not Error(...). This example should either be removed or replaced with a correct example that shows successful wrapping of a value in Ok.

Suggested change
// task { return Error (System.Exception("error")) }
// task { return Ok (System.Exception("error")) }

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 2cba7f5 — corrected the comment to Ok (System.Exception("error")) since ofTask just wraps the value in Ok without catching anything.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@copilot this is not acceptable. You need to show the error case properly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 46b4928 — Example 2 now shows that a throwing task has its exception propagate out (not caught/wrapped in Error).

Comment thread src/FsToolkit.ErrorHandling/TaskResult.fs Outdated

@TheAngryByrd TheAngryByrd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@copilot, review other copilot comments

Co-authored-by: TheAngryByrd <1490044+TheAngryByrd@users.noreply.github.com>
Co-authored-by: TheAngryByrd <1490044+TheAngryByrd@users.noreply.github.com>
@TheAngryByrd
TheAngryByrd merged commit 9cf1c54 into master Feb 25, 2026
26 checks passed
TheAngryByrd added a commit that referenced this pull request Feb 27, 2026
- [Add IAsyncEnumerable support to task computation expressions](#347) Credits @Copilot
- [Add `valueTaskValueOption` CE for `ValueTask<'T voption>` computation expressions](#348) Credits @Copilot
- [Add `cancellableValueTaskOption` and `cancellableValueTaskResult` CEs for IcedTasks](#349) Credits @Copilot
- [Add `Source` overloads to `taskResultOption` CE for interop with `Result`, `TaskResult`, `Option`, `Task`, and `Async`](#351) Credits @Copilot
- [Add `requireSomeWith` and `requireNoneWith` for lazy error evaluation](#352) Credits @Copilot
- [Add `TaskResult.ofCatchTask`](#353) Credits @Copilot
- [Add comprehensive gitbook documentation for all public API surface](#354) Credits @Copilot
TheAngryByrd added a commit that referenced this pull request Feb 27, 2026
- [Add IAsyncEnumerable support to task computation expressions](#347) Credits @Copilot
- [Add `valueTaskValueOption` CE for `ValueTask<'T voption>` computation expressions](#348) Credits @Copilot
- [Add `cancellableValueTaskOption` and `cancellableValueTaskResult` CEs for IcedTasks](#349) Credits @Copilot
- [Add `Source` overloads to `taskResultOption` CE for interop with `Result`, `TaskResult`, `Option`, `Task`, and `Async`](#351) Credits @Copilot
- [Add `requireSomeWith` and `requireNoneWith` for lazy error evaluation](#352) Credits @Copilot
- [Add `TaskResult.ofCatchTask`](#353) Credits @Copilot
- [Add comprehensive gitbook documentation for all public API surface](#354) Credits @Copilot
TheAngryByrd added a commit that referenced this pull request Feb 27, 2026
- [Add IAsyncEnumerable support to task computation expressions](#347) Credits @Copilot
- [Add `valueTaskValueOption` CE for `ValueTask<'T voption>` computation expressions](#348) Credits @Copilot
- [Add `cancellableValueTaskOption` and `cancellableValueTaskResult` CEs for IcedTasks](#349) Credits @Copilot
- [Add `Source` overloads to `taskResultOption` CE for interop with `Result`, `TaskResult`, `Option`, `Task`, and `Async`](#351) Credits @Copilot
- [Add `requireSomeWith` and `requireNoneWith` for lazy error evaluation](#352) Credits @Copilot
- [Add `TaskResult.ofCatchTask`](#353) Credits @Copilot
- [Add comprehensive gitbook documentation for all public API surface](#354) Credits @Copilot

Remove AutoGPT subproject reference
TheAngryByrd added a commit that referenced this pull request Feb 27, 2026
- [Add IAsyncEnumerable support to task computation expressions](#347) Credits @Copilot
- [Add `valueTaskValueOption` CE for `ValueTask<'T voption>` computation expressions](#348) Credits @Copilot
- [Add `cancellableValueTaskOption` and `cancellableValueTaskResult` CEs for IcedTasks](#349) Credits @Copilot
- [Add `Source` overloads to `taskResultOption` CE for interop with `Result`, `TaskResult`, `Option`, `Task`, and `Async`](#351) Credits @Copilot
- [Add `requireSomeWith` and `requireNoneWith` for lazy error evaluation](#352) Credits @Copilot
- [Add `TaskResult.ofCatchTask`](#353) Credits @Copilot
- [Add comprehensive gitbook documentation for all public API surface](#354) Credits @Copilot

Remove AutoGPT subproject reference
TheAngryByrd added a commit that referenced this pull request Feb 27, 2026
- [Add IAsyncEnumerable support to task computation expressions](#347) Credits @Copilot
- [Add `valueTaskValueOption` CE for `ValueTask<'T voption>` computation expressions](#348) Credits @Copilot
- [Add `cancellableValueTaskOption` and `cancellableValueTaskResult` CEs for IcedTasks](#349) Credits @Copilot
- [Add `Source` overloads to `taskResultOption` CE for interop with `Result`, `TaskResult`, `Option`, `Task`, and `Async`](#351) Credits @Copilot
- [Add `requireSomeWith` and `requireNoneWith` for lazy error evaluation](#352) Credits @Copilot
- [Add `TaskResult.ofCatchTask`](#353) Credits @Copilot
- [Add comprehensive gitbook documentation for all public API surface](#354) Credits @Copilot
TheAngryByrd added a commit that referenced this pull request Feb 27, 2026
- [Add IAsyncEnumerable support to task computation expressions](#347) Credits @Copilot
- [Add `valueTaskValueOption` CE for `ValueTask<'T voption>` computation expressions](#348) Credits @Copilot
- [Add `cancellableValueTaskOption` and `cancellableValueTaskResult` CEs for IcedTasks](#349) Credits @Copilot
- [Add `Source` overloads to `taskResultOption` CE for interop with `Result`, `TaskResult`, `Option`, `Task`, and `Async`](#351) Credits @Copilot
- [Add `requireSomeWith` and `requireNoneWith` for lazy error evaluation](#352) Credits @Copilot
- [Add `TaskResult.ofCatchTask`](#353) Credits @Copilot
- [Add comprehensive gitbook documentation for all public API surface](#354) Credits @Copilot

Remove AutoGPT subproject reference
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.

TaskResult.ofTask

3 participants