Error Handling Example¶
Error handling patterns:
1#!/usr/bin/env python
2"""
342 Error Handling - Robust Error Management
4
5Learn how to handle various error types and implement retry logic.
6
7Level: Expert Topic
8"""
9
10from config_loader import get_chat_config, parse_args
11
12from lexilux import Chat
13from lexilux.exceptions import (
14 APIError,
15 AuthenticationError,
16 ConnectionError as LexiluxConnectionError,
17 InvalidRequestError,
18 RateLimitError,
19 TimeoutError as LexiluxTimeoutError,
20)
21
22
23def main():
24 """Demonstrate comprehensive error handling."""
25 args = parse_args()
26 try:
27 config = get_chat_config(config_path=args.config)
28 except (FileNotFoundError, KeyError) as e:
29 print(f"Configuration error: {e}")
30 print("\nUsing placeholder values. Please configure test_endpoints.json")
31 config = {
32 "base_url": "https://api.example.com/v1",
33 "api_key": "your-api-key",
34 "model": "gpt-4",
35 }
36
37 chat = Chat(**config)
38
39 # Example 1: Basic error handling
40 print("=" * 50)
41 print("Example 1: Basic Error Handling")
42 print("=" * 50)
43
44 try:
45 result = chat("Hello, world!")
46 print(f"Response: {result.text}")
47 except AuthenticationError as e:
48 print(f"Authentication failed: {e.message}")
49 print(" Check your API key")
50 except RateLimitError as e:
51 print(f"Rate limited: {e.message}")
52 print(f" Retryable: {e.retryable}")
53 except LexiluxTimeoutError as e:
54 print(f"Request timed out: {e.message}")
55 print(f" Retryable: {e.retryable}")
56 except APIError as e:
57 print(f"API error: {e.code} - {e.message}")
58
59 # Example 2: Specific error handling
60 print("\n" + "=" * 50)
61 print("Example 2: Handle Specific Errors Differently")
62 print("=" * 50)
63
64 def safe_chat(prompt: str) -> str | None:
65 """Chat with comprehensive error handling."""
66 try:
67 result = chat(prompt)
68 return result.text
69 except AuthenticationError:
70 print("❌ Authentication failed - check your API key")
71 return None
72 except RateLimitError:
73 print("⏱️ Rate limited - please wait a moment")
74 return None
75 except InvalidRequestError as e:
76 print(f"❌ Invalid request: {e.message}")
77 return None
78 except LexiluxConnectionError:
79 print("❌ Connection failed - check your network")
80 return None
81 except LexiluxTimeoutError:
82 print("⏱️ Request timed out - try again")
83 return None
84 except APIError as e:
85 print(f"❌ API error ({e.code}): {e.message}")
86 return None
87
88 response = safe_chat("Hello!")
89 if response:
90 print(f"✓ Got response: {response[:50]}...\n")
91
92 # Example 3: Retry logic
93 print("=" * 50)
94 print("Example 3: Implement Retry Logic")
95 print("=" * 50)
96
97 import time
98
99 def chat_with_retry(
100 prompt: str,
101 max_retries: int = 3,
102 base_delay: float = 1.0,
103 ) -> str | None:
104 """Chat with exponential backoff retry."""
105 for attempt in range(max_retries):
106 try:
107 result = chat(prompt)
108 return result.text
109 except RateLimitError as e:
110 if e.retryable and attempt < max_retries - 1:
111 delay = base_delay * (2**attempt)
112 print(
113 f"Rate limited. Waiting {delay:.1f}s... "
114 f"(attempt {attempt + 1}/{max_retries})"
115 )
116 time.sleep(delay)
117 else:
118 print(f"Rate limit exceeded after {max_retries} attempts")
119 return None
120 except APIError as e:
121 if e.retryable and attempt < max_retries - 1:
122 delay = base_delay * (2**attempt)
123 print(
124 f"Temporary error. Retrying in {delay:.1f}s... "
125 f"(attempt {attempt + 1}/{max_retries})"
126 )
127 time.sleep(delay)
128 else:
129 print(f"Failed after {max_retries} attempts: {e.message}")
130 return None
131 return None
132
133 response = chat_with_retry("Hello with retry!")
134 if response:
135 print(f"✓ Success: {response[:50]}...\n")
136
137 # Example 4: Streaming error handling
138 print("=" * 50)
139 print("Example 4: Handle Errors in Streaming")
140 print("=" * 50)
141
142 print("Streaming with error handling:\n")
143
144 try:
145 got_response = False
146 for chunk in chat.stream("Tell me a joke"):
147 if chunk.delta:
148 print(chunk.delta, end="", flush=True)
149 got_response = True
150
151 if chunk.done:
152 print("\n✓ Streaming completed successfully")
153 print(f"Tokens: {chunk.usage.total_tokens}\n")
154 break
155 else:
156 # Loop completed without done=True
157 if got_response:
158 print("\n⚠️ Stream interrupted before completion")
159 else:
160 print("\n❌ No content received")
161
162 except AuthenticationError as e:
163 print(f"\n❌ Authentication failed: {e.message}")
164 except RateLimitError as e:
165 print(f"\n❌ Rate limited: {e.message}")
166 except APIError as e:
167 print(f"\n❌ API error: {e.code} - {e.message}")
168
169 # Example 5: Validate input before request
170 print("=" * 50)
171 print("Example 5: Input Validation")
172 print("=" * 50)
173
174 def validated_chat(prompt: str, max_length: int = 10000) -> str | None:
175 """Chat with input validation."""
176 # Validate input
177 if not prompt or not prompt.strip():
178 print("❌ Empty prompt")
179 return None
180
181 if len(prompt) > max_length:
182 print(f"❌ Prompt too long ({len(prompt)} > {max_length})")
183 return None
184
185 # Make request
186 try:
187 result = chat(prompt)
188 return result.text
189 except APIError as e:
190 print(f"❌ Request failed: {e.message}")
191 return None
192
193 # Test validation
194 result = validated_chat("Valid prompt")
195 if result:
196 print(f"✓ Valid request succeeded: {result[:50]}...\n")
197
198 result = validated_chat("")
199 print("✓ Empty prompt caught\n")
200
201 # Example 6: Error context for debugging
202 print("=" * 50)
203 print("Example 6: Extract Error Context")
204 print("=" * 50)
205
206 try:
207 # Use invalid model to trigger error
208 bad_chat = Chat(
209 base_url=config["base_url"],
210 api_key=config["api_key"],
211 model="nonexistent-model-12345",
212 )
213 bad_chat("This will fail")
214 except APIError as e:
215 print("Error details:")
216 print(f" Type: {type(e).__name__}")
217 print(f" Code: {e.code}")
218 print(f" Message: {e.message}")
219 print(f" Retryable: {e.retryable}")
220 if hasattr(e, "response"):
221 print(f" Status code: {getattr(e.response, 'status_code', 'N/A')}")
222
223 print("\n✓ Error handling completed!")
224
225
226if __name__ == "__main__":
227 main()