Skip to content

Fault the run when a render pass throws a foreign OperationCanceledException [patch] - #253

Open
matt-edmondson wants to merge 1 commit into
mainfrom
fix/248-render-oce-faults-run
Open

matt-edmondson wants to merge 1 commit into
mainfrom
fix/248-render-oce-faults-run

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #248

What changed

#216 made an OperationCanceledException that doesn't come from cancelling the run fault RunAsync, but only on the input path. #247 let render failures escape the input loop, and that path had no wrap. So a foreign OCE thrown during a pass (from a Post action, an element's OnRender, or the initial Render()) passed through RunAsync's general catch { throw; }. Leaving an async method, that made the task Canceled, and a host read it as a clean shutdown.

UIApplication now has a private RenderDuringRun(CancellationToken) helper, called from the initial render in RunAsync and from both passes in ProcessInputAsync. When a pass throws an OCE and the run's token is not cancelled, the helper wraps it in InvalidOperationException, keeping the original as the inner exception, the same way the input path does. An OCE that does come from cancelling the run passes through unchanged, so a shutdown during a pass still ends the run quietly. Render() called directly behaves as before.

Tests

New tests in UIApplicationRenderFailureTests:

  • AForeignCancellationOnTheFirstPassFaultsTheRun: the initial render
  • AForeignCancellationFromAPostedActionFaultsTheRun: the issue's Post repro
  • AForeignCancellationOnThePassAfterAKeyFaultsTheRun: an OnRender that starts throwing after a key
  • CancellingTheRunDuringAPassStillEndsItQuietly: guards the run's own cancellation

The first three check for a Faulted run with an InvalidOperationException whose inner exception is the original TaskCanceledException. With the UIApplication change reverted, all three fail and the fourth still passes. With it in place, the full suite passes (331/331).


Generated by Claude Code

…nceledException

Since #247 a render failure escapes the input loop, but nothing wrapped
an OperationCanceledException that didn't come from cancelling the run.
Leaving the async RunAsync, it made the task Canceled, so a Post action
that hit an HttpClient timeout looked like a clean shutdown. The initial
pass and both passes in the input loop now go through RenderDuringRun,
which wraps it in InvalidOperationException as the input path does.

Fixes #248

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW4towbdqS7BHdCDNqm
@sonarqubecloud

sonarqubecloud Bot commented Nov 6, 2026

Copy link
Copy Markdown

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.

An OperationCanceledException from a render pass or a Post action ends RunAsync as Canceled instead of Faulted (#216 still happens on the render path)

2 participants