@@ -39,6 +39,10 @@ class XaiDeviceCode:
3939 interval : float
4040
4141
42+ class _InvalidGrantError (ProviderKeyError ):
43+ pass
44+
45+
4246def _oauth_error (action : str , response : httpx .Response ) -> ProviderKeyError :
4347 try :
4448 payload = response .json ()
@@ -54,6 +58,15 @@ def _oauth_error(action: str, response: httpx.Response) -> ProviderKeyError:
5458 )
5559
5660
61+ def _oauth_error_code (response : httpx .Response ) -> str | None :
62+ try :
63+ payload = response .json ()
64+ except ValueError :
65+ return None
66+ error = payload .get ("error" ) if isinstance (payload , dict ) else None
67+ return error if isinstance (error , str ) else None
68+
69+
5770def _required_string (payload : dict [str , Any ], field : str ) -> str :
5871 value = payload .get (field )
5972 if not isinstance (value , str ) or not value :
@@ -190,7 +203,10 @@ def refresh_xai_credential(
190203 },
191204 )
192205 if not response .is_success :
193- raise _oauth_error ("token refresh" , response )
206+ error = _oauth_error ("token refresh" , response )
207+ if _oauth_error_code (response ) == "invalid_grant" :
208+ raise _InvalidGrantError (error .message , error .details )
209+ raise error
194210 payload = response .json ()
195211 if not isinstance (payload , dict ):
196212 raise ProviderKeyError ("Invalid xAI OAuth response" , "Expected a JSON object." )
@@ -243,7 +259,11 @@ def get_xai_access_token(
243259 credential = current .credential
244260 expired = credential .expires_at is not None and time .time () >= credential .expires_at
245261 if force_refresh or expired :
246- credential = refresh_xai_credential (credential , client = client )
262+ try :
263+ credential = refresh_xai_credential (credential , client = client )
264+ except _InvalidGrantError :
265+ delete_oauth_credential (XAI_PROVIDER_ID )
266+ return None
247267 save_oauth_credential (
248268 XAI_PROVIDER_ID ,
249269 credential ,
0 commit comments