From d24da263c7ef4ae8bc8ce9d6596ca775e8e718ed Mon Sep 17 00:00:00 2001 From: Hector Morales Date: Wed, 20 May 2026 17:21:36 -0700 Subject: [PATCH 1/3] fix: preserve CacheError errorCode through cache save path and convert to BrowserAuthError - CacheManager.saveCacheRecord: re-throw CacheError without wrapping, preserving original errorCode - BrowserCacheManager.saveCacheRecord: convert CacheError to BrowserAuthError so callers can call setCorrelationId - Add tests for both behaviors Fixes SharePoint telemetry showing 'e.setCorrelationId is not a function' because CacheError does not extend AuthError. The errorCode was also being lost due to double-wrapping (CacheError('cacheQuotaExceeded') -> CacheError('CacheError')). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/cache/BrowserCacheManager.ts | 33 +++++++++--------- .../test/cache/BrowserCacheManager.spec.ts | 8 ++++- lib/msal-common/src/cache/CacheManager.ts | 4 ++- .../test/cache/CacheManager.spec.ts | 34 +++++++++++++++++++ 4 files changed, 60 insertions(+), 19 deletions(-) diff --git a/lib/msal-browser/src/cache/BrowserCacheManager.ts b/lib/msal-browser/src/cache/BrowserCacheManager.ts index 9286a0d694..4a69e79457 100644 --- a/lib/msal-browser/src/cache/BrowserCacheManager.ts +++ b/lib/msal-browser/src/cache/BrowserCacheManager.ts @@ -2347,23 +2347,22 @@ export class BrowserCacheManager extends CacheManager { storeInCache ); } catch (e) { - if ( - e instanceof CacheError && - this.performanceClient && - correlationId - ) { - try { - const tokenKeys = this.getTokenKeys(); - - this.performanceClient.addFields( - { - cacheRtCount: tokenKeys.refreshToken.length, - cacheIdCount: tokenKeys.idToken.length, - cacheAtCount: tokenKeys.accessToken.length, - }, - correlationId - ); - } catch (e) {} + if (e instanceof CacheError) { + if (this.performanceClient && correlationId) { + try { + const tokenKeys = this.getTokenKeys(); + + this.performanceClient.addFields( + { + cacheRtCount: tokenKeys.refreshToken.length, + cacheIdCount: tokenKeys.idToken.length, + cacheAtCount: tokenKeys.accessToken.length, + }, + correlationId + ); + } catch (e) {} + } + throw createBrowserAuthError(e.errorCode); } throw e; diff --git a/lib/msal-browser/test/cache/BrowserCacheManager.spec.ts b/lib/msal-browser/test/cache/BrowserCacheManager.spec.ts index 75a6b38497..6e611ed3d6 100644 --- a/lib/msal-browser/test/cache/BrowserCacheManager.spec.ts +++ b/lib/msal-browser/test/cache/BrowserCacheManager.spec.ts @@ -4311,7 +4311,13 @@ describe("BrowserCacheManager tests", () => { ); }) .catch((e) => { - expect(e).toBeInstanceOf(CacheError); + expect(e).toBeInstanceOf(BrowserAuthError); + expect(e.errorCode).toEqual( + CacheErrorCodes.cacheQuotaExceeded + ); + expect( + typeof e.setCorrelationId + ).toBe("function"); measurement.end({ success: false }, e); }) ); diff --git a/lib/msal-common/src/cache/CacheManager.ts b/lib/msal-common/src/cache/CacheManager.ts index cdb489155d..a773144a5c 100644 --- a/lib/msal-common/src/cache/CacheManager.ts +++ b/lib/msal-common/src/cache/CacheManager.ts @@ -14,7 +14,7 @@ import { getAliasesFromStaticSources } from "../authority/AuthorityMetadata.js"; import { StaticAuthorityOptions } from "../authority/AuthorityOptions.js"; import { ICrypto } from "../crypto/ICrypto.js"; import { AuthError } from "../error/AuthError.js"; -import { createCacheError } from "../error/CacheError.js"; +import { CacheError, createCacheError } from "../error/CacheError.js"; import { ClientAuthErrorCodes, createClientAuthError, @@ -660,6 +660,8 @@ export abstract class CacheManager implements ICacheManager { ); if (e instanceof AuthError) { throw e; + } else if (e instanceof CacheError) { + throw e; } else { throw createCacheError(e); } diff --git a/lib/msal-common/test/cache/CacheManager.spec.ts b/lib/msal-common/test/cache/CacheManager.spec.ts index 9c4fc65b72..2047ef5d9f 100644 --- a/lib/msal-common/test/cache/CacheManager.spec.ts +++ b/lib/msal-common/test/cache/CacheManager.spec.ts @@ -7,6 +7,7 @@ import { buildAccountFromIdTokenClaims, buildIdToken } from "msal-test-utils"; import { AccountInfo } from "../../src/account/AccountInfo.js"; import * as authorityMetadata from "../../src/authority/AuthorityMetadata.js"; import { CacheManager } from "../../src/cache/CacheManager.js"; +import { CacheError, CacheErrorCodes } from "../../src/error/CacheError.js"; import { AccessTokenEntity } from "../../src/cache/entities/AccessTokenEntity.js"; import { AccountEntity } from "../../src/cache/entities/AccountEntity.js"; import { AppMetadataEntity } from "../../src/cache/entities/AppMetadataEntity.js"; @@ -333,6 +334,39 @@ describe("CacheManager.ts test cases", () => { ); expect(mockCacheRT).toBe(null); }); + + it("preserves CacheError errorCode when setAccessTokenCredential throws CacheError", async () => { + const at = CacheHelpers.createAccessTokenEntity( + TEST_ACCOUNT_INFO.homeAccountId, + TEST_ACCOUNT_INFO.environment, + TEST_TOKENS.ACCESS_TOKEN, + TEST_CONFIG.MSAL_CLIENT_ID, + TEST_CONFIG.MSAL_TENANT_ID, + "User.Read", + TEST_TOKEN_LIFETIMES.TEST_ACCESS_TOKEN_EXP, + TEST_TOKEN_LIFETIMES.TEST_ACCESS_TOKEN_EXP, + mockCrypto.base64Decode + ); + const cacheRecord: CacheRecord = { accessToken: at }; + + jest.spyOn( + mockCache.cacheManager, + "setAccessTokenCredential" + ).mockRejectedValue( + new CacheError(CacheErrorCodes.cacheQuotaExceeded) + ); + + await expect( + mockCache.cacheManager.saveCacheRecord( + cacheRecord, + TEST_CONFIG.CORRELATION_ID, + true, + 0 + ) + ).rejects.toMatchObject({ + errorCode: CacheErrorCodes.cacheQuotaExceeded, + }); + }); }); describe("getAllAccounts", () => { From b0c42927ce9d8be8faeaf61d21cbd2e7ea9165d8 Mon Sep 17 00:00:00 2001 From: Hector Morales Date: Wed, 20 May 2026 17:41:14 -0700 Subject: [PATCH 2/3] chore: add beachball changefiles for msal-common and msal-browser Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...-msal-browser-877cf768-037a-49b5-88a6-3d64d0c34514.json | 7 +++++++ ...e-msal-common-507be680-4d41-45db-af72-09e4378a1da8.json | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 change/@azure-msal-browser-877cf768-037a-49b5-88a6-3d64d0c34514.json create mode 100644 change/@azure-msal-common-507be680-4d41-45db-af72-09e4378a1da8.json diff --git a/change/@azure-msal-browser-877cf768-037a-49b5-88a6-3d64d0c34514.json b/change/@azure-msal-browser-877cf768-037a-49b5-88a6-3d64d0c34514.json new file mode 100644 index 0000000000..4a1a653473 --- /dev/null +++ b/change/@azure-msal-browser-877cf768-037a-49b5-88a6-3d64d0c34514.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: convert CacheError to BrowserAuthError in saveCacheRecord so callers can call setCorrelationId", + "packageName": "@azure/msal-browser", + "email": "hemoral@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@azure-msal-common-507be680-4d41-45db-af72-09e4378a1da8.json b/change/@azure-msal-common-507be680-4d41-45db-af72-09e4378a1da8.json new file mode 100644 index 0000000000..4ef690a175 --- /dev/null +++ b/change/@azure-msal-common-507be680-4d41-45db-af72-09e4378a1da8.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: re-throw existing CacheError without re-wrapping to preserve original errorCode", + "packageName": "@azure/msal-common", + "email": "hemoral@microsoft.com", + "dependentChangeType": "patch" +} From 332764c1ab2445e83a70895e6f5bde4623c71380 Mon Sep 17 00:00:00 2001 From: Hector Morales Date: Wed, 20 May 2026 17:50:45 -0700 Subject: [PATCH 3/3] chore: update apiReview and test after format pass Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../test/cache/BrowserCacheManager.spec.ts | 6 +- lib/msal-common/apiReview/msal-common.api.md | 72 +++++++++---------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/msal-browser/test/cache/BrowserCacheManager.spec.ts b/lib/msal-browser/test/cache/BrowserCacheManager.spec.ts index 6e611ed3d6..83602eb02e 100644 --- a/lib/msal-browser/test/cache/BrowserCacheManager.spec.ts +++ b/lib/msal-browser/test/cache/BrowserCacheManager.spec.ts @@ -4315,9 +4315,9 @@ describe("BrowserCacheManager tests", () => { expect(e.errorCode).toEqual( CacheErrorCodes.cacheQuotaExceeded ); - expect( - typeof e.setCorrelationId - ).toBe("function"); + expect(typeof e.setCorrelationId).toBe( + "function" + ); measurement.end({ success: false }, e); }) ); diff --git a/lib/msal-common/apiReview/msal-common.api.md b/lib/msal-common/apiReview/msal-common.api.md index d49b2c6bbc..3eebc1cbbc 100644 --- a/lib/msal-common/apiReview/msal-common.api.md +++ b/lib/msal-common/apiReview/msal-common.api.md @@ -4843,42 +4843,42 @@ const X_MS_LIB_CAPABILITY_VALUE: string; // src/authority/AuthorityOptions.ts:25:5 - (ae-forgotten-export) The symbol "CloudInstanceDiscoveryResponse" needs to be exported by the entry point index.d.ts // src/cache/CacheManager.ts:355:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // src/cache/CacheManager.ts:356:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:671:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1631:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1632:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1646:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1647:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1667:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1668:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1677:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1678:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1694:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1695:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1711:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1712:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1726:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1727:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1765:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1766:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1780:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1781:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1792:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1793:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1804:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1805:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1816:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1817:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1834:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1835:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1864:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1865:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1884:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1885:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1904:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1905:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1916:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1917:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen -// src/cache/CacheManager.ts:1925:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:673:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1633:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1634:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1648:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1649:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1669:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1670:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1679:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1680:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1696:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1697:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1713:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1714:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1728:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1729:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1767:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1768:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1782:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1783:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1794:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1795:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1806:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1807:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1818:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1819:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1836:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1837:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1866:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1867:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1886:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1887:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1906:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1907:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1918:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1919:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen +// src/cache/CacheManager.ts:1927:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen // src/cache/entities/AccountEntity.ts:49:5 - (ae-forgotten-export) The symbol "DataBoundary" needs to be exported by the entry point index.d.ts // src/cache/utils/CacheTypes.ts:94:53 - (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag // src/cache/utils/CacheTypes.ts:94:43 - (tsdoc-malformed-html-name) Invalid HTML element: An HTML name must be an ASCII letter followed by zero or more letters, digits, or hyphens