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()