3939 tqdm ,
4040 validate_hf_hub_args ,
4141)
42- from .utils ._http import _adjust_range_header , http_backoff , http_stream_backoff
42+ from .utils ._http import (
43+ _DEFAULT_RETRY_ON_EXCEPTIONS ,
44+ _DEFAULT_RETRY_ON_STATUS_CODES ,
45+ _adjust_range_header ,
46+ http_backoff ,
47+ http_stream_backoff ,
48+ )
4349from .utils ._runtime import is_xet_available
4450from .utils ._typing import HTTP_METHOD_T
4551from .utils .sha import sha_fileobj
@@ -267,30 +273,38 @@ def hf_hub_url(
267273 return url
268274
269275
270- def _httpx_follow_relative_redirects (method : HTTP_METHOD_T , url : str , ** httpx_kwargs ) -> httpx .Response :
276+ def _httpx_follow_relative_redirects (
277+ method : HTTP_METHOD_T , url : str , * , retry_on_errors : bool = False , ** httpx_kwargs
278+ ) -> httpx .Response :
271279 """Perform an HTTP request with backoff and follow relative redirects only.
272280
273281 This is useful to follow a redirection to a renamed repository without following redirection to a CDN.
274282
275- A backoff mechanism retries the HTTP call on 5xx errors and network errors.
283+ A backoff mechanism retries the HTTP call on errors (429, 5xx, timeout, network errors) .
276284
277285 Args:
278286 method (`str`):
279287 HTTP method, such as 'GET' or 'HEAD'.
280288 url (`str`):
281289 The URL of the resource to fetch.
290+ retry_on_errors (`bool`, *optional*, defaults to `False`):
291+ Whether to retry on errors. If False, no retry is performed (fast fallback to local cache).
292+ If True, uses default retry behavior (429, 5xx, timeout, network errors).
282293 **httpx_kwargs (`dict`, *optional*):
283294 Params to pass to `httpx.request`.
284295 """
296+ # if `retry_on_errors=False`, disable all retries for fast fallback to cache
297+ no_retry_kwargs : dict [str , Any ] = (
298+ {} if retry_on_errors else {"retry_on_exceptions" : (), "retry_on_status_codes" : ()}
299+ )
300+
285301 while True :
286- # Make the request
287302 response = http_backoff (
288303 method = method ,
289304 url = url ,
290305 ** httpx_kwargs ,
291306 follow_redirects = False ,
292- retry_on_exceptions = (),
293- retry_on_status_codes = (429 ,),
307+ ** no_retry_kwargs ,
294308 )
295309 hf_raise_for_status (response )
296310
@@ -1134,9 +1148,11 @@ def _hf_hub_download_to_cache_dir(
11341148 if not force_download :
11351149 return pointer_path
11361150
1137- # No local file found, retry with longer timeout if it was a timeout error
1138- if isinstance (head_call_error , httpx .TimeoutException ):
1139- logger .info ("Metadata fetch timed out and no local file found. Retrying with longer timeout.." )
1151+ if isinstance (head_call_error , _DEFAULT_RETRY_ON_EXCEPTIONS ) or (
1152+ isinstance (head_call_error , HfHubHTTPError )
1153+ and head_call_error .response .status_code in _DEFAULT_RETRY_ON_STATUS_CODES
1154+ ):
1155+ logger .info ("No local file found. Retrying.." )
11401156 (url_to_download , etag , commit_hash , expected_size , xet_file_data , head_call_error ) = (
11411157 _get_metadata_or_catch_error (
11421158 repo_id = repo_id ,
@@ -1150,6 +1166,7 @@ def _hf_hub_download_to_cache_dir(
11501166 local_files_only = local_files_only ,
11511167 storage_folder = storage_folder ,
11521168 relative_filename = relative_filename ,
1169+ retry_on_errors = True ,
11531170 )
11541171 )
11551172
@@ -1323,22 +1340,26 @@ def _hf_hub_download_to_local_dir(
13231340 )
13241341 if not force_download :
13251342 return local_path
1326- elif not force_download and isinstance (head_call_error , httpx .TimeoutException ):
1327- # No local file found, retry with longer timeout if it was a timeout error
1328- logger .info ("Metadata fetch timed out and no local file found. Retrying with longer timeout..." )
1329- (url_to_download , etag , commit_hash , expected_size , xet_file_data , head_call_error ) = (
1330- _get_metadata_or_catch_error (
1331- repo_id = repo_id ,
1332- filename = filename ,
1333- repo_type = repo_type ,
1334- revision = revision ,
1335- endpoint = endpoint ,
1336- etag_timeout = _ETAG_RETRY_TIMEOUT ,
1337- headers = headers ,
1338- token = token ,
1339- local_files_only = local_files_only ,
1343+ elif not force_download :
1344+ if isinstance (head_call_error , _DEFAULT_RETRY_ON_EXCEPTIONS ) or (
1345+ isinstance (head_call_error , HfHubHTTPError )
1346+ and head_call_error .response .status_code in _DEFAULT_RETRY_ON_STATUS_CODES
1347+ ):
1348+ logger .info ("No local file found. Retrying.." )
1349+ (url_to_download , etag , commit_hash , expected_size , xet_file_data , head_call_error ) = (
1350+ _get_metadata_or_catch_error (
1351+ repo_id = repo_id ,
1352+ filename = filename ,
1353+ repo_type = repo_type ,
1354+ revision = revision ,
1355+ endpoint = endpoint ,
1356+ etag_timeout = _ETAG_RETRY_TIMEOUT ,
1357+ headers = headers ,
1358+ token = token ,
1359+ local_files_only = local_files_only ,
1360+ retry_on_errors = True ,
1361+ )
13401362 )
1341- )
13421363
13431364 # If still error, raise
13441365 if head_call_error is not None :
@@ -1547,6 +1568,7 @@ def get_hf_file_metadata(
15471568 user_agent : Union [dict , str , None ] = None ,
15481569 headers : Optional [dict [str , str ]] = None ,
15491570 endpoint : Optional [str ] = None ,
1571+ retry_on_errors : bool = False ,
15501572) -> HfFileMetadata :
15511573 """Fetch metadata of a file versioned on the Hub for a given url.
15521574
@@ -1571,6 +1593,9 @@ def get_hf_file_metadata(
15711593 Additional headers to be sent with the request.
15721594 endpoint (`str`, *optional*):
15731595 Endpoint of the Hub. Defaults to <https://huggingface.co>.
1596+ retry_on_errors (`bool`, *optional*, defaults to `False`):
1597+ Whether to retry on errors (429, 5xx, timeout, network errors).
1598+ If False, no retry for fast fallback to local cache.
15741599
15751600 Returns:
15761601 A [`HfFileMetadata`] object containing metadata such as location, etag, size and
@@ -1586,7 +1611,9 @@ def get_hf_file_metadata(
15861611 hf_headers ["Accept-Encoding" ] = "identity" # prevent any compression => we want to know the real size of the file
15871612
15881613 # Retrieve metadata
1589- response = _httpx_follow_relative_redirects (method = "HEAD" , url = url , headers = hf_headers , timeout = timeout )
1614+ response = _httpx_follow_relative_redirects (
1615+ method = "HEAD" , url = url , headers = hf_headers , timeout = timeout , retry_on_errors = retry_on_errors
1616+ )
15901617 hf_raise_for_status (response )
15911618
15921619 # Return
@@ -1619,6 +1646,7 @@ def _get_metadata_or_catch_error(
16191646 local_files_only : bool ,
16201647 relative_filename : Optional [str ] = None , # only used to store `.no_exists` in cache
16211648 storage_folder : Optional [str ] = None , # only used to store `.no_exists` in cache
1649+ retry_on_errors : bool = False ,
16221650) -> Union [
16231651 # Either an exception is caught and returned
16241652 tuple [None , None , None , None , None , Exception ],
@@ -1661,7 +1689,12 @@ def _get_metadata_or_catch_error(
16611689 try :
16621690 try :
16631691 metadata = get_hf_file_metadata (
1664- url = url , timeout = etag_timeout , headers = headers , token = token , endpoint = endpoint
1692+ url = url ,
1693+ timeout = etag_timeout ,
1694+ headers = headers ,
1695+ token = token ,
1696+ endpoint = endpoint ,
1697+ retry_on_errors = retry_on_errors ,
16651698 )
16661699 except RemoteEntryNotFoundError as http_error :
16671700 if storage_folder is not None and relative_filename is not None :
0 commit comments