Skip to content

[ci-fix] Use DoNotWrapExceptions across ReflectionMemberAccessor Invoke paths#129212

Draft
github-actions[bot] wants to merge 9 commits into
mainfrom
ci-fix/reflection-unwrap-tie-128766-da9341c6f0fcce74
Draft

[ci-fix] Use DoNotWrapExceptions across ReflectionMemberAccessor Invoke paths#129212
github-actions[bot] wants to merge 9 commits into
mainfrom
ci-fix/reflection-unwrap-tie-128766-da9341c6f0fcce74

Conversation

@github-actions

@github-actions github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Workflow artifact: ci-fix
Artifact kind: help
Linked KBE: #128766

> [!NOTE]
> This is an AI/Copilot-generated fix updated after PR feedback and validated with targeted local build/test runs.

Root cause (best analysis)

AsyncEnumerableTests.SerializeAsyncEnumerable_*_PartialItemFailure_PriorItemsAreFullyWritten fails on tvos-arm64 AllSubsets_Mono because the test expects InvalidOperationException but receives TargetInvocationException.

The failing log line:

[FAIL] ...AsyncEnumerableTests_AsyncPipeSerializer.SerializeAsyncEnumerable_TopLevelValues_PartialItemFailure_PriorItemsAreFullyWritten
Expected: typeof(System.InvalidOperationException)
Actual:   typeof(System.Reflection.TargetInvocationException)

On Mono/tvOS (AOT environments), System.Text.Json uses ReflectionMemberAccessor, where reflection Invoke can wrap target exceptions. CoreCLR commonly uses ReflectionEmitMemberAccessor, which propagates underlying exceptions directly.

Attempted fix

Updated ReflectionMemberAccessor to apply BindingFlags.DoNotWrapExceptions on NET targets across relevant reflection Invoke call sites in the file (including property accessors and other Invoke usages raised in review), while preserving non-NET compatibility paths.

Additional polish from feedback:

  • Kept exception behavior aligned with ReflectionEmitMemberAccessor for add-method delegate behavior.
  • Improved null-handling/diagnostics for union accessor delegate creation.

What is unverified / where I need help

  • Full matrix/platform validation (especially tvOS Mono) still depends on CI legs; local validation was targeted.

Validation

  • ./build.sh clr+libs -rc release
  • ./build.sh clr+libs+host -rc release -lc release
  • dotnet build src/libraries/System.Text.Json/src/System.Text.Json.csproj -c Release
  • dotnet build /t:test src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj -p:Configuration=Release /p:XunitMethodName=System.Text.Json.Serialization.Tests.AsyncEnumerableTests_AsyncPipeSerializer.SerializeAsyncEnumerable_TopLevelValues_PartialItemFailure_PriorItemsAreFullyWritten

Evidence

Help wanted

  • Area owners (area-System.Text.Json): @StephenMolloy, @dotnet/area-system-text-json

Filed by ci-failure-fix. Comment here or on the workflow file to suggest changes; ci-failure-scan-feedback reads in-scope feedback daily and opens (or updates) a PR with prompt edits.

> [!WARNING]
>

> Generated by CI Outer-Loop Failure Fixer · ● 35M ·

… accessors

On Mono/tvOS (AOT environments), System.Text.Json uses ReflectionMemberAccessor
which calls MethodInfo.Invoke() for property getters/setters. This wraps any
exception thrown by the property in TargetInvocationException, unlike CoreCLR
which uses IL-emitted delegates that propagate exceptions directly.

The constructor delegates in the same class already unwrap
TargetInvocationException; this commit adds the same treatment to
CreatePropertyGetter and CreatePropertySetter using
ExceptionDispatchInfo.Capture to preserve the original stack trace.

Fixes the tvOS Mono test failure where
AsyncEnumerableTests.SerializeAsyncEnumerable_PartialItemFailure tests
expect InvalidOperationException but receive TargetInvocationException.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@kotlarmilos kotlarmilos changed the title [ci-fix] Needs review: Unwrap TargetInvocationException in ReflectionMemberAccessor property accessors (refs #128766) [ci-fix] Unwrap TargetInvocationException in ReflectionMemberAccessor property accessors Jun 10, 2026
Co-authored-by: kotlarmilos <11523312+kotlarmilos@users.noreply.github.com>
Copilot AI requested a review from kotlarmilos June 16, 2026 10:49
{
return (TProperty)getMethodInfo.Invoke(obj, null)!;
#if NET
return (TProperty)getMethodInfo.Invoke(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There are other Invoke method calls in this file. Do all of them need the same treatment?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@copilot resolve this 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.

Addressed in 6e9eede. I audited the other Invoke call sites in ReflectionMemberAccessor and updated them to use BindingFlags.DoNotWrapExceptions on NET (with existing non-NET compatibility paths preserved).

Copilot AI and others added 6 commits June 17, 2026 07:11
Co-authored-by: kotlarmilos <11523312+kotlarmilos@users.noreply.github.com>
Co-authored-by: kotlarmilos <11523312+kotlarmilos@users.noreply.github.com>
Co-authored-by: kotlarmilos <11523312+kotlarmilos@users.noreply.github.com>
Co-authored-by: kotlarmilos <11523312+kotlarmilos@users.noreply.github.com>
Co-authored-by: kotlarmilos <11523312+kotlarmilos@users.noreply.github.com>
Co-authored-by: kotlarmilos <11523312+kotlarmilos@users.noreply.github.com>
Copilot AI changed the title [ci-fix] Unwrap TargetInvocationException in ReflectionMemberAccessor property accessors [ci-fix] Use DoNotWrapExceptions across ReflectionMemberAccessor Invoke paths Jun 17, 2026
parameters: new object[] { element! },
culture: null);
#else
addMethod.Invoke(collection, new object[] { element! });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this catch and rethrow the exception like the other cases?

@@ -130,6 +164,7 @@ public override JsonTypeInfo.ParameterizedConstructorDelegate<T, TArg0, TArg1, T
{
throw e.InnerException ?? e;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should the pattern for catch and rethrow be consistent across all cases?

if (accessor is null)
{
throw new InvalidOperationException(
$"Failed to create union accessor for type '{entry.Key}' using method '{entry.Value}'.");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This unrelated change. It should be left for separate PR (and tests should be added to cover it in that PR)

@github-actions github-actions Bot mentioned this pull request Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants