@@ -74,16 +74,120 @@ export const skill = async function (event, context) {
7474 const accessToken = extractAccessTokenFromEvent ( event )
7575 event . profile = await fetchProfile ( accessToken )
7676 } catch ( e ) {
77+ // Enhanced error logging for token-related failures
78+ const accessToken = extractAccessTokenFromEvent ( event )
79+ const tokenPrefix = accessToken ?. substring ( 0 , 12 ) + '...'
80+
81+ // Determine the error type and appropriate response
82+ let errorType = 'EXPIRED_AUTHORIZATION_CREDENTIAL'
83+ let errorMessage = 'invalid token'
84+ let shouldDisableSkill = true
85+
86+ // Handle ProfileFetchError specifically
87+ if ( e . name === 'ProfileFetchError' ) {
88+ if ( e . isRetryable && ! e . isAuthError ) {
89+ // Network/server errors should not disable the skill
90+ errorType = 'INTERNAL_ERROR'
91+ errorMessage = 'temporary service unavailable'
92+ shouldDisableSkill = false
93+
94+ log . warn ( 'NETWORK/SERVER ERROR detected - NOT disabling skill' , {
95+ directive : event . directive ?. header ?. name ,
96+ tokenPrefix,
97+ errorCategory : e . errorCategory ,
98+ status : e . status ,
99+ isRetryable : e . isRetryable ,
100+ isAuthError : e . isAuthError ,
101+ responseData : e . responseData ,
102+ requestId : context ?. awsRequestId
103+ } )
104+ } else if ( e . isAuthError ) {
105+ // Actual auth errors should disable the skill
106+ shouldDisableSkill = true
107+
108+ log . error ( 'AUTHENTICATION ERROR detected - skill may be disabled' , {
109+ directive : event . directive ?. header ?. name ,
110+ tokenPrefix,
111+ errorCategory : e . errorCategory ,
112+ status : e . status ,
113+ isAuthError : e . isAuthError ,
114+ responseData : e . responseData ,
115+ requestId : context ?. awsRequestId
116+ } )
117+ }
118+ }
119+
120+ log . error ( 'Skill authentication failed' , {
121+ directive : event . directive ?. header ?. name ,
122+ tokenPrefix,
123+ errorName : e . name ,
124+ errorMessage : e . message ,
125+ errorStack : e . stack ,
126+ requestId : context ?. awsRequestId ,
127+ userId : event . profile ?. user_id || 'unknown' ,
128+ errorType,
129+ shouldDisableSkill,
130+ // Enhanced classification for ProfileFetchError
131+ errorCategory : e . errorCategory || 'unknown' ,
132+ isRetryable : e . isRetryable || false ,
133+ isAuthError : e . isAuthError || false ,
134+ // Check if this is a token refresh error
135+ isTokenRefreshError : e . name === 'UserTokenRefreshError' || e . name === 'TokenRefreshError' ,
136+ originalTokenError : e . originalError ?. message ,
137+ tokenStatus : e . status ,
138+ responseData : e . responseData
139+ } )
140+
141+ // Log specific patterns that indicate different failure types
142+ if ( e . name === 'UserTokenRefreshError' || e . name === 'TokenRefreshError' ) {
143+ log . error ( 'TOKEN REFRESH FAILURE detected - potential skill auto-disable cause' , {
144+ userId : e . userId || 'unknown' ,
145+ refreshTokenPrefix : e . refreshTokenPrefix ,
146+ tokenExpiry : e . tokenExpiry ,
147+ httpStatus : e . status ,
148+ amazonResponse : e . responseData
149+ } )
150+ } else if ( e . name === 'ProfileFetchError' && e . errorCategory === 'NETWORK_ERROR' ) {
151+ log . warn ( 'NETWORK ERROR on profile fetch - should NOT cause skill disable' , {
152+ tokenPrefix,
153+ errorCategory : e . errorCategory ,
154+ errorCode : e . originalError ?. code ,
155+ likelyCase : 'Temporary network/DNS/timeout issue'
156+ } )
157+ } else if ( e . name === 'ProfileFetchError' && e . errorCategory === 'SERVER_ERROR' ) {
158+ log . warn ( 'AMAZON API SERVER ERROR - should NOT cause skill disable' , {
159+ tokenPrefix,
160+ status : e . status ,
161+ errorCategory : e . errorCategory ,
162+ likelyCase : 'Amazon API temporary downtime/overload'
163+ } )
164+ } else if ( e . message ?. includes ( '401' ) || e . message ?. includes ( '403' ) ||
165+ ( e . name === 'ProfileFetchError' && e . isAuthError ) ) {
166+ log . error ( 'HTTP AUTH ERROR detected' , {
167+ tokenPrefix,
168+ httpError : e . message ,
169+ errorCategory : e . errorCategory || 'unknown' ,
170+ likelyCase : 'User revoked permissions or client credentials changed'
171+ } )
172+ } else if ( e . message ?. includes ( 'invalid_grant' ) ) {
173+ log . error ( 'INVALID_GRANT ERROR detected' , {
174+ tokenPrefix,
175+ likelyCase : 'Refresh token expired, user permissions revoked, or client config changed'
176+ } )
177+ }
178+
77179 const response = createErrorResponse (
78180 event ,
79- 'EXPIRED_AUTHORIZATION_CREDENTIAL' ,
80- 'invalid token'
181+ errorType ,
182+ errorMessage
81183 )
184+
82185 log . notice (
83- 'REQUEST: %j \n EXCEPTION: %o \n RESPONSE: %j' ,
186+ 'REQUEST: %j \n EXCEPTION: %o \n RESPONSE: %j \n SKILL_DISABLE_RISK: %s ' ,
84187 event ,
85188 e ,
86- response
189+ response ,
190+ shouldDisableSkill ? 'HIGH' : 'LOW'
87191 )
88192 return response
89193 }
0 commit comments