Skip to content

Surface AuthenticationResultMetadata on non-MSAL failures via Exception.Data (3696194) - #6140

Merged
neha-bhargava merged 1 commit into
nebharg/otel-enricher-nonmsal-exceptionfrom
nebharg/nonmsal-metadata-exdata
Jul 22, 2026
Merged

Surface AuthenticationResultMetadata on non-MSAL failures via Exception.Data (3696194)#6140
neha-bhargava merged 1 commit into
nebharg/otel-enricher-nonmsal-exceptionfrom
nebharg/nonmsal-metadata-exdata

Conversation

@neha-bhargava

Copy link
Copy Markdown
Contributor

Bug

3696194 — token-acquisition metadata (durations, cache-refresh reason, token endpoint, region) is null on the failure path when the failure is a non-MsalException (e.g. an HttpRequestException thrown from a FIC client-assertion callback). Downstream header-creation providers read metadata off the caught exception; MSAL 4.86.0 (#6096) already covers the MsalException-origin case via MsalException.AuthenticationResultMetadata, leaving only the non-MSAL-origin gap.

Change

On the non-MsalException failure path, MSAL now stashes the failure AuthenticationResultMetadata on the original exception's Data bag under a new public, documented key MsalException.AuthenticationResultMetadataKey. The typed object is stored (not flattened primitives) so consumers can reuse their existing AuthenticationResultMetadata mappers verbatim.

  • The original exception is re-thrown unchanged — MSAL does not wrap/convert it (that would be a breaking change).
  • The write is guarded (if (ex.Data is { IsReadOnly: false })) so telemetry plumbing can never mask the caller's real exception.
  • Exception.Data is the only built-in per-instance bag that survives a re-throw.

Notes

@neha-bhargava
neha-bhargava requested a review from a team as a code owner July 21, 2026 21:36
…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
neha-bhargava force-pushed the nebharg/nonmsal-metadata-exdata branch from b9c9a21 to 25c7f47 Compare July 22, 2026 18:33
@neha-bhargava
neha-bhargava merged commit 54626e2 into nebharg/otel-enricher-nonmsal-exception Jul 22, 2026
3 checks passed
@neha-bhargava
neha-bhargava deleted the nebharg/nonmsal-metadata-exdata branch July 22, 2026 18:40
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
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.

3 participants