@@ -184,6 +184,53 @@ const ERROR_EXTRACTORS: ErrorExtractorConfig[] = [
184184 examples : [ 'Microsoft OAuth' , 'Google OAuth' , 'OAuth2 providers' ] ,
185185 extract : ( errorInfo ) => errorInfo ?. data ?. error_description ,
186186 } ,
187+ {
188+ id : 'microsoft-graph-errors' ,
189+ description :
190+ 'Microsoft Graph error format with nested innerError chain and details[] (Excel, OneDrive, SharePoint, Outlook). See https://learn.microsoft.com/en-us/graph/errors' ,
191+ examples : [ 'Microsoft Excel' , 'Microsoft OneDrive' , 'Microsoft SharePoint' ] ,
192+ extract : ( errorInfo ) => {
193+ const data = errorInfo ?. data
194+ if ( ! data || typeof data !== 'object' ) return undefined
195+
196+ const root = ( data as { error ?: any } ) . error
197+ if ( root && typeof root === 'object' ) {
198+ const messages : string [ ] = [ ]
199+ if ( typeof root . message === 'string' && root . message . trim ( ) ) {
200+ messages . push ( root . message . trim ( ) )
201+ }
202+
203+ // Walk nested innerError chain. Spec uses `innererror` (lowercase),
204+ // Graph commonly returns `innerError` — accept both. Cap depth.
205+ let inner : any = root . innererror ?? root . innerError
206+ let depth = 0
207+ while ( inner && depth < 5 ) {
208+ if ( typeof inner . message === 'string' && inner . message . trim ( ) ) {
209+ const msg = inner . message . trim ( )
210+ if ( ! messages . includes ( msg ) ) messages . push ( msg )
211+ }
212+ inner = inner . innererror ?? inner . innerError
213+ depth ++
214+ }
215+
216+ if ( Array . isArray ( root . details ) ) {
217+ for ( const detail of root . details ) {
218+ if ( detail && typeof detail . message === 'string' && detail . message . trim ( ) ) {
219+ const msg = detail . message . trim ( )
220+ if ( ! messages . includes ( msg ) ) messages . push ( msg )
221+ }
222+ }
223+ }
224+
225+ if ( messages . length > 0 ) return messages . join ( ' — ' )
226+ if ( typeof root . code === 'string' && root . code . trim ( ) ) return root . code . trim ( )
227+ }
228+
229+ const topMessage = ( data as { message ?: unknown } ) . message
230+ if ( typeof topMessage === 'string' && topMessage . trim ( ) ) return topMessage . trim ( )
231+ return undefined
232+ } ,
233+ } ,
187234 {
188235 id : 'nested-error-object' ,
189236 description : 'Error field containing nested object or string' ,
@@ -260,6 +307,7 @@ export function extractErrorMessage(errorInfo?: ErrorInfo, extractorId?: string)
260307
261308export const ErrorExtractorId = {
262309 ATLASSIAN_ERRORS : 'atlassian-errors' ,
310+ MICROSOFT_GRAPH_ERRORS : 'microsoft-graph-errors' ,
263311 GRAPHQL_ERRORS : 'graphql-errors' ,
264312 TWITTER_ERRORS : 'twitter-errors' ,
265313 DETAILS_ARRAY : 'details-array' ,
0 commit comments