Surface AuthenticationResultMetadata on non-MSAL failures via Exception.Data (3696194) - #6140
Merged
neha-bhargava merged 1 commit intoJul 22, 2026
Conversation
bgavrilMS
approved these changes
Jul 22, 2026
gladjohn
approved these changes
Jul 22, 2026
…n.Data (Bug 3696194) When a token acquisition fails with a non-MsalException, MSAL now stashes the failure AuthenticationResultMetadata (durations, cache-refresh reason, token endpoint, region) on the original exception's Data bag under the new public MsalException.AuthenticationResultMetadataKey. Downstream header-creation providers that catch the raw exception can surface token-acquisition diagnostics without MSAL converting or wrapping the thrown exception. The original exception is re-thrown unchanged; the write is guarded so it never masks the caller's exception. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d296b5aa-33db-4934-a697-cdf1c1999e09
neha-bhargava
force-pushed
the
nebharg/nonmsal-metadata-exdata
branch
from
July 22, 2026 18:33
b9c9a21 to
25c7f47
Compare
neha-bhargava
merged commit Jul 22, 2026
54626e2
into
nebharg/otel-enricher-nonmsal-exception
3 checks passed
neha-bhargava
added a commit
that referenced
this pull request
Jul 22, 2026
#6139) * Populate ExecutionResult.Exception for non-MSAL failures (Bug 3696306) The OTel tags enricher received ExecutionResult.Exception = null when a token acquisition failed with a non-MsalException, because RequestBase's generic catch passed no exception to LogFailureTelemetryToOtel. It now hands the enricher a telemetry-only MsalException wrapper (originating type as ErrorCode, original message, original exception as InnerException, plus failure metadata), mirroring the MsalException path. The original exception is still re-thrown unchanged, so caller-observable behavior is unaffected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d296b5aa-33db-4934-a697-cdf1c1999e09 * Guard telemetry-only wrapper against empty message/null type name (Bug 3696306) Address PR review: the non-MSAL enricher wrapper used ex.GetType().FullName and ex.Message directly, but the MsalException ctor rejects a null/whitespace errorCode or errorMessage. An original exception with an empty message (or a null Type.FullName for some generic/array types) would therefore raise an ArgumentNullException that replaced the original exception, breaking the rethrow-unchanged guarantee. Fall back to the type name in both cases and add a regression test for the empty-message path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d296b5aa-33db-4934-a697-cdf1c1999e09 * Surface AuthenticationResultMetadata on non-MSAL failures via Exception.Data (3696194) (#6140) Expose AuthenticationResultMetadata on non-MSAL failures via Exception.Data (Bug 3696194) When a token acquisition fails with a non-MsalException, MSAL now stashes the failure AuthenticationResultMetadata (durations, cache-refresh reason, token endpoint, region) on the original exception's Data bag under the new public MsalException.AuthenticationResultMetadataKey. Downstream header-creation providers that catch the raw exception can surface token-acquisition diagnostics without MSAL converting or wrapping the thrown exception. The original exception is re-thrown unchanged; the write is guarded so it never masks the caller's exception. Copilot-Session: d296b5aa-33db-4934-a697-cdf1c1999e09 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Mark AuthenticationResultMetadata [Serializable] on .NET Framework/netstandard (3696194) The Exception.Data write added for 3696194 throws ArgumentException 'not serializable' on .NET Framework, whose ListDictionaryInternal rejects non-serializable values, replacing the caller's original exception (17 net48 test failures). .NET Core removed that check. Mark AuthenticationResultMetadata and its RegionDetails member [Serializable] only under NETFRAMEWORK || NETSTANDARD; the whole graph is serializable so the write succeeds on every target and metadata is delivered uniformly. No public-API or test changes needed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d296b5aa-33db-4934-a697-cdf1c1999e09 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d296b5aa-33db-4934-a697-cdf1c1999e09
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
3696194 — token-acquisition metadata (durations, cache-refresh reason, token endpoint, region) is
nullon the failure path when the failure is a non-MsalException(e.g. anHttpRequestExceptionthrown from a FIC client-assertion callback). Downstream header-creation providers read metadata off the caught exception; MSAL 4.86.0 (#6096) already covers theMsalException-origin case viaMsalException.AuthenticationResultMetadata, leaving only the non-MSAL-origin gap.Change
On the non-
MsalExceptionfailure path, MSAL now stashes the failureAuthenticationResultMetadataon the original exception'sDatabag under a new public, documented keyMsalException.AuthenticationResultMetadataKey. The typed object is stored (not flattened primitives) so consumers can reuse their existingAuthenticationResultMetadatamappers verbatim.if (ex.Data is { IsReadOnly: false })) so telemetry plumbing can never mask the caller's real exception.Exception.Datais the only built-in per-instance bag that survives a re-throw.Notes
const stringkey + PublicAPI.Unshipped entries (6 TFMs). No behavioral change to the thrown exception.