"""Pinecone SDK exception hierarchy."""
from __future__ import annotations
TYPE_CHECKING = False
if TYPE_CHECKING:
from typing import Any
[docs]
class PineconeError(Exception):
"""Base exception for all Pinecone SDK errors."""
[docs]
def __init__(self, message: str) -> None:
self.message = message
super().__init__(message)
[docs]
class ApiError(PineconeError):
"""Server returned an error response."""
[docs]
def __init__(
self,
message: str,
status_code: int,
body: dict[str, Any] | None = None,
*,
reason: str | None = None,
headers: dict[str, str] | None = None,
error_code: str | None = None,
request_id: str | None = None,
) -> None:
self.status_code = status_code
self.body = body
self.reason = reason
self.headers = headers
self.error_code = error_code
self.request_id = request_id
super().__init__(message)
def __str__(self) -> str:
try:
prefix = f"{self.status_code}"
if self.error_code:
prefix = f"{prefix} {self.error_code}"
base = f"[{prefix}] {self.message}"
if self.request_id:
base = f"{base} (request_id: {self.request_id})"
return base
except Exception:
# Never let __str__ raise — that would mask the original error.
try:
return f"[{self.status_code}] {self.message}"
except Exception:
return "<ApiError: unrenderable>"
def __repr__(self) -> str:
try:
msg = self.message
if len(msg) > 100:
msg = msg[:97] + "..."
except Exception:
msg = "<unrenderable>"
parts = [
f"status_code={self.status_code}",
f"message={msg!r}",
]
if self.error_code is not None:
parts.append(f"error_code={self.error_code!r}")
if self.request_id is not None:
parts.append(f"request_id={self.request_id!r}")
if self.body is not None:
try:
parts.append(f"body={self.body!r}")
except Exception:
parts.append("body=<unrenderable>")
return f"{type(self).__name__}({', '.join(parts)})"
[docs]
class NotFoundError(ApiError):
"""404 Not Found."""
[docs]
def __init__(
self,
message: str = "Resource not found",
status_code: int = 404,
body: dict[str, Any] | None = None,
*,
reason: str | None = None,
headers: dict[str, str] | None = None,
error_code: str | None = None,
request_id: str | None = None,
) -> None:
super().__init__(
message=message,
status_code=status_code,
body=body,
reason=reason,
headers=headers,
error_code=error_code,
request_id=request_id,
)
[docs]
class ConflictError(ApiError):
"""409 Conflict."""
[docs]
def __init__(
self,
message: str = "Resource conflict",
status_code: int = 409,
body: dict[str, Any] | None = None,
*,
reason: str | None = None,
headers: dict[str, str] | None = None,
error_code: str | None = None,
request_id: str | None = None,
) -> None:
super().__init__(
message=message,
status_code=status_code,
body=body,
reason=reason,
headers=headers,
error_code=error_code,
request_id=request_id,
)
[docs]
class UnauthorizedError(ApiError):
"""401 Unauthorized."""
[docs]
def __init__(
self,
message: str = "Invalid or missing API key",
status_code: int = 401,
body: dict[str, Any] | None = None,
*,
reason: str | None = None,
headers: dict[str, str] | None = None,
error_code: str | None = None,
request_id: str | None = None,
) -> None:
super().__init__(
message=message,
status_code=status_code,
body=body,
reason=reason,
headers=headers,
error_code=error_code,
request_id=request_id,
)
[docs]
class ForbiddenError(ApiError):
"""403 Forbidden."""
[docs]
def __init__(
self,
message: str = "Forbidden",
status_code: int = 403,
body: dict[str, Any] | None = None,
*,
reason: str | None = None,
headers: dict[str, str] | None = None,
error_code: str | None = None,
request_id: str | None = None,
) -> None:
super().__init__(
message=message,
status_code=status_code,
body=body,
reason=reason,
headers=headers,
error_code=error_code,
request_id=request_id,
)
[docs]
class ServiceError(ApiError):
"""5xx server error."""
[docs]
def __init__(
self,
message: str = "Internal server error",
status_code: int = 500,
body: dict[str, Any] | None = None,
*,
reason: str | None = None,
headers: dict[str, str] | None = None,
error_code: str | None = None,
request_id: str | None = None,
) -> None:
super().__init__(
message=message,
status_code=status_code,
body=body,
reason=reason,
headers=headers,
error_code=error_code,
request_id=request_id,
)
[docs]
class IndexInitFailedError(PineconeError):
"""Raised when an index fails to initialize."""
[docs]
def __init__(self, index_name: str) -> None:
super().__init__(f"Index '{index_name}' entered InitializationFailed state")
self.index_name = index_name
[docs]
class PineconeTimeoutError(PineconeError, TimeoutError):
"""Raised when an operation exceeds its timeout.
Multiply inherits from Python's built-in :class:`TimeoutError` so that
``except TimeoutError`` blocks in caller code catch SDK timeouts without
having to import a Pinecone-specific class. This is the same pattern used
by :class:`PineconeValueError` (extends :class:`ValueError`).
"""
[docs]
class PineconeConnectionError(PineconeError):
"""Raised when a network-level connection fails.
Covers DNS resolution failures, connection refused, read/write errors,
and other transport-level problems.
"""
pass
[docs]
class PineconeValueError(PineconeError, ValueError):
"""Input validation failed — invalid value."""
[docs]
def __init__(self, message: str, path: str | None = None) -> None:
self.path = path
super().__init__(message)
def __str__(self) -> str:
try:
if isinstance(self.path, str) and self.path:
return f"at {self.path}: {self.message}"
return self.message
except Exception:
return self.message if isinstance(self.message, str) else super().__str__()
[docs]
class PineconeTypeError(PineconeError, TypeError):
"""Input validation failed — wrong type."""
[docs]
def __init__(self, message: str, path: str | None = None) -> None:
self.path = path
super().__init__(message)
def __str__(self) -> str:
try:
if isinstance(self.path, str) and self.path:
return f"at {self.path}: {self.message}"
return self.message
except Exception:
return self.message if isinstance(self.message, str) else super().__str__()
[docs]
class ResponseParsingError(PineconeError):
"""Raised when the SDK fails to parse an API response body.
Wraps the underlying deserialization error (e.g. ``msgspec.ValidationError``)
so that callers' ``except PineconeError`` blocks always catch it.
"""
[docs]
def __init__(self, message: str, cause: Exception | None = None) -> None:
self.cause = cause
super().__init__(message)
def __str__(self) -> str:
try:
if self.cause is None:
return self.message
cause_name = type(self.cause).__name__
try:
cause_str = str(self.cause)
except Exception:
cause_str = "<unrenderable>"
return f"{self.message} (caused by {cause_name}: {cause_str})"
except Exception:
return self.message if isinstance(self.message, str) else super().__str__()
# Backwards-compatible alias — most validation is value validation
ValidationError = PineconeValueError # Deprecated: use PineconeValueError instead
# ---------------------------------------------------------------------------
# Legacy name aliases — :meta private:
# New code should use the canonical names above.
# ---------------------------------------------------------------------------
# Backcompat alias, :meta private:
PineconeException = PineconeError
# Backcompat alias, :meta private:
PineconeApiException = ApiError
# Backcompat alias, :meta private:
NotFoundException = NotFoundError
# Backcompat alias, :meta private:
UnauthorizedException = UnauthorizedError
# Backcompat alias, :meta private:
ForbiddenException = ForbiddenError
# Backcompat alias, :meta private:
ServiceException = ServiceError
# Backcompat alias, :meta private:
PineconeConfigurationError = PineconeValueError
# Backcompat alias, :meta private:
PineconeProtocolError = PineconeError
# Backcompat alias, :meta private:
PineconeApiTypeError = PineconeTypeError
# Backcompat alias, :meta private:
PineconeApiValueError = PineconeValueError
# Backcompat alias, :meta private:
PineconeApiAttributeError = PineconeError
# Backcompat alias, :meta private:
PineconeApiKeyError = PineconeError
# Backcompat alias, :meta private:
ListConversionException = PineconeError