main
1# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
3from __future__ import annotations
4
5from typing import TYPE_CHECKING, Any, Optional, cast
6from typing_extensions import Literal
7
8import httpx
9
10from ._utils import is_dict
11from ._models import construct_type
12
13if TYPE_CHECKING:
14 from .types.chat import ChatCompletion
15
16__all__ = [
17 "BadRequestError",
18 "AuthenticationError",
19 "PermissionDeniedError",
20 "NotFoundError",
21 "ConflictError",
22 "UnprocessableEntityError",
23 "RateLimitError",
24 "InternalServerError",
25 "LengthFinishReasonError",
26 "ContentFilterFinishReasonError",
27 "InvalidWebhookSignatureError",
28]
29
30
31class OpenAIError(Exception):
32 pass
33
34
35class APIError(OpenAIError):
36 message: str
37 request: httpx.Request
38
39 body: object | None
40 """The API response body.
41
42 If the API responded with a valid JSON structure then this property will be the
43 decoded result.
44
45 If it isn't a valid JSON structure then this will be the raw response.
46
47 If there was no response associated with this error then it will be `None`.
48 """
49
50 code: Optional[str] = None
51 param: Optional[str] = None
52 type: Optional[str]
53
54 def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None:
55 super().__init__(message)
56 self.request = request
57 self.message = message
58 self.body = body
59
60 if is_dict(body):
61 self.code = cast(Any, construct_type(type_=Optional[str], value=body.get("code")))
62 self.param = cast(Any, construct_type(type_=Optional[str], value=body.get("param")))
63 self.type = cast(Any, construct_type(type_=str, value=body.get("type")))
64 else:
65 self.code = None
66 self.param = None
67 self.type = None
68
69
70class APIResponseValidationError(APIError):
71 response: httpx.Response
72 status_code: int
73
74 def __init__(self, response: httpx.Response, body: object | None, *, message: str | None = None) -> None:
75 super().__init__(message or "Data returned by API invalid for expected schema.", response.request, body=body)
76 self.response = response
77 self.status_code = response.status_code
78
79
80class APIStatusError(APIError):
81 """Raised when an API response has a status code of 4xx or 5xx."""
82
83 response: httpx.Response
84 status_code: int
85 request_id: str | None
86
87 def __init__(self, message: str, *, response: httpx.Response, body: object | None) -> None:
88 super().__init__(message, response.request, body=body)
89 self.response = response
90 self.status_code = response.status_code
91 self.request_id = response.headers.get("x-request-id")
92
93
94class APIConnectionError(APIError):
95 def __init__(self, *, message: str = "Connection error.", request: httpx.Request) -> None:
96 super().__init__(message, request, body=None)
97
98
99class APITimeoutError(APIConnectionError):
100 def __init__(self, request: httpx.Request) -> None:
101 super().__init__(message="Request timed out.", request=request)
102
103
104class BadRequestError(APIStatusError):
105 status_code: Literal[400] = 400 # pyright: ignore[reportIncompatibleVariableOverride]
106
107
108class AuthenticationError(APIStatusError):
109 status_code: Literal[401] = 401 # pyright: ignore[reportIncompatibleVariableOverride]
110
111
112class PermissionDeniedError(APIStatusError):
113 status_code: Literal[403] = 403 # pyright: ignore[reportIncompatibleVariableOverride]
114
115
116class NotFoundError(APIStatusError):
117 status_code: Literal[404] = 404 # pyright: ignore[reportIncompatibleVariableOverride]
118
119
120class ConflictError(APIStatusError):
121 status_code: Literal[409] = 409 # pyright: ignore[reportIncompatibleVariableOverride]
122
123
124class UnprocessableEntityError(APIStatusError):
125 status_code: Literal[422] = 422 # pyright: ignore[reportIncompatibleVariableOverride]
126
127
128class RateLimitError(APIStatusError):
129 status_code: Literal[429] = 429 # pyright: ignore[reportIncompatibleVariableOverride]
130
131
132class InternalServerError(APIStatusError):
133 pass
134
135
136class LengthFinishReasonError(OpenAIError):
137 completion: ChatCompletion
138 """The completion that caused this error.
139
140 Note: this will *not* be a complete `ChatCompletion` object when streaming as `usage`
141 will not be included.
142 """
143
144 def __init__(self, *, completion: ChatCompletion) -> None:
145 msg = "Could not parse response content as the length limit was reached"
146 if completion.usage:
147 msg += f" - {completion.usage}"
148
149 super().__init__(msg)
150 self.completion = completion
151
152
153class ContentFilterFinishReasonError(OpenAIError):
154 def __init__(self) -> None:
155 super().__init__(
156 f"Could not parse response content as the request was rejected by the content filter",
157 )
158
159
160class InvalidWebhookSignatureError(ValueError):
161 """Raised when a webhook signature is invalid, meaning the computed signature does not match the expected signature."""