File size: 4,420 Bytes
fa63d67 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | # Copyright 2026 The HuggingFace Team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""CLI error handling utilities."""
import traceback
from collections.abc import Callable
from huggingface_hub.errors import (
BucketNotFoundError,
CLIError,
CLIExtensionInstallError,
GatedRepoError,
HfHubHTTPError,
LocalTokenNotFoundError,
RemoteEntryNotFoundError,
RepositoryNotFoundError,
RevisionNotFoundError,
)
def _format_repo_not_found(error: RepositoryNotFoundError) -> str:
label = error.repo_type.capitalize() if error.repo_type else "Repository"
if error.repo_id:
msg = f"{label} '{error.repo_id}' not found."
else:
msg = f"{label} not found."
msg += " If the repo is private, make sure you are authenticated and your token has the required permissions."
return msg
def _format_gated_repo(error: GatedRepoError) -> str:
label = error.repo_type if error.repo_type else "repository"
if error.repo_id:
return f"Access denied. {label.capitalize()} '{error.repo_id}' requires approval."
return f"Access denied. This {label} requires approval."
def _format_bucket_not_found(error: BucketNotFoundError) -> str:
if error.bucket_id:
return f"Bucket '{error.bucket_id}' not found. If the bucket is private, make sure you are authenticated and your token has the required permissions."
return "Bucket not found. Check the bucket id (namespace/name). If the bucket is private, make sure you are authenticated and your token has the required permissions."
def _format_entry_not_found(error: RemoteEntryNotFoundError) -> str:
label = error.repo_type if error.repo_type else "repository"
url = str(error.response.url) if error.response else None
if error.repo_id:
msg = f"File not found in {label} '{error.repo_id}'."
else:
msg = f"File not found in {label}."
if url:
msg += f"\nURL: {url}"
return msg
def _format_revision_not_found(error: RevisionNotFoundError) -> str:
label = error.repo_type if error.repo_type else "repository"
if error.repo_id:
return f"Revision not found in {label} '{error.repo_id}'."
return f"Revision not found in {label}. Check the revision parameter."
def _format_cli_error(error: CLIError) -> str:
"""No traceback, just the error message."""
return str(error)
def _format_cli_extension_install_error(error: CLIExtensionInstallError) -> str:
"""Format a CLI extension installation error.
The error is likely to be a tricky subprocess error to investigate. In this specific case we want to format the
traceback of the root cause while keeping the "nicely formatted" error message of the CLIExtensionInstallError
as a 1-line message.
"""
cause_tb = (
"".join(traceback.format_exception(type(error.__cause__), error.__cause__, error.__cause__.__traceback__))
if error.__cause__ is not None
else ""
)
return f"{cause_tb}\n{error}"
CLI_ERROR_MAPPINGS: dict[type[Exception], Callable[..., str]] = {
# GatedRepoError must come before RepositoryNotFoundError (it's a subclass).
GatedRepoError: _format_gated_repo,
BucketNotFoundError: _format_bucket_not_found,
RepositoryNotFoundError: _format_repo_not_found,
RevisionNotFoundError: _format_revision_not_found,
LocalTokenNotFoundError: lambda _: "Not logged in. Run 'hf auth login' first.",
RemoteEntryNotFoundError: _format_entry_not_found,
HfHubHTTPError: lambda error: str(error),
ValueError: lambda error: f"Invalid value. {error}",
CLIExtensionInstallError: _format_cli_extension_install_error,
CLIError: _format_cli_error,
}
def format_known_exception(error: Exception) -> str | None:
for exc_type, formatter in CLI_ERROR_MAPPINGS.items():
if isinstance(error, exc_type):
return formatter(error)
return None
|