Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.baytos.ai/llms.txt

Use this file to discover all available pages before exploring further.

Error Handling

Learn how to handle errors, implement retry strategies, and build resilient applications with the Claro Python SDK.

Exception Hierarchy

The SDK provides a hierarchy of exceptions for different error types:
BaytAPIError (base class)
├── BaytAuthError (401, 403)
├── BaytNotFoundError (404)
├── BaytRateLimitError (429)
└── BaytValidationError (400)
All SDK exceptions inherit from BaytAPIError, allowing you to catch all SDK errors with a single handler.

Exception Types

BaytAuthError

Authentication and authorization errors (HTTP 401, 403):
from baytos.claro import BaytClient, BaytAuthError

try:
    client = BaytClient(api_key="invalid_key")
    prompt = client.get_prompt("@workspace/test:v1")
except BaytAuthError as e:
    print(f"Authentication failed: {e}")
    print("Please check your API key")
Common causes:
  • Invalid or expired API key
  • Insufficient permissions
  • Workspace access denied

BaytNotFoundError

Resource not found errors (HTTP 404):
from baytos.claro import BaytClient, BaytNotFoundError

client = BaytClient(api_key="your_api_key")

try:
    prompt = client.get_prompt("@workspace/nonexistent:v1")
except BaytNotFoundError as e:
    print(f"Prompt not found: {e}")
    print("Check the package name and version")
Common causes:
  • Incorrect package name
  • Wrong version number
  • Prompt deleted or moved
  • No access to the workspace

BaytRateLimitError

Rate limit exceeded (HTTP 429):
from baytos.claro import BaytClient, BaytRateLimitError
import time

client = BaytClient(api_key="your_api_key")

try:
    prompt = client.get_prompt("@workspace/test:v1")
except BaytRateLimitError as e:
    print(f"Rate limited: {e}")
    print("Waiting before retry...")
    time.sleep(60)  # Wait 1 minute
Note: The SDK automatically retries on 429 with exponential backoff. This exception is only raised after all retries are exhausted.

BaytValidationError

Invalid request parameters (HTTP 400):
from baytos.claro import BaytClient, BaytValidationError

client = BaytClient(api_key="your_api_key")

try:
    # Invalid limit
    result = client.list_prompts(limit=200)
except BaytValidationError as e:
    print(f"Validation error: {e}")
Common causes:
  • Invalid package name format
  • Out of range parameters (e.g., limit > 100)
  • Missing required fields

BaytAPIError

Base exception for all API errors:
from baytos.claro import BaytClient, BaytAPIError

client = BaytClient(api_key="your_api_key")

try:
    prompt = client.get_prompt("@workspace/test:v1")
except BaytAPIError as e:
    print(f"API error: {e}")
    # Catches all SDK errors
Includes:
  • Network errors
  • Server errors (5xx)
  • Timeout errors
  • All specific exceptions above

Basic Error Handling

Catch Specific Errors

Handle different error types appropriately:
from baytos.claro import (
    BaytClient,
    BaytAuthError,
    BaytNotFoundError,
    BaytRateLimitError,
    BaytValidationError,
    BaytAPIError
)

client = BaytClient(api_key="your_api_key")

try:
    prompt = client.get_prompt("@workspace/my-prompt:v1")
    print(f"Success: {prompt.title}")

except BaytAuthError:
    # Handle authentication errors
    print("Authentication failed. Check your API key.")
    print("Get a new key at: https://claro.baytos.ai")

except BaytNotFoundError:
    # Handle not found errors
    print("Prompt not found. Check the package name.")

except BaytRateLimitError:
    # Handle rate limiting
    print("Rate limit exceeded. Please wait and try again.")

except BaytValidationError as e:
    # Handle validation errors
    print(f"Invalid request: {e}")

except BaytAPIError as e:
    # Handle other API errors
    print(f"API error: {e}")

except Exception as e:
    # Handle unexpected errors
    print(f"Unexpected error: {e}")

Catch All SDK Errors

Use the base exception to catch all SDK errors:
from baytos.claro import BaytClient, BaytAPIError

client = BaytClient(api_key="your_api_key")

try:
    prompt = client.get_prompt("@workspace/test:v1")
except BaytAPIError as e:
    # Handles all SDK exceptions
    print(f"SDK error: {e}")
    # Log to your error tracking system

Retry Strategies

Built-in Retries

The SDK automatically retries on rate limits and server errors:
from baytos.claro import BaytClient

# Default: 3 retries with exponential backoff
client = BaytClient(api_key="your_api_key", max_retries=3)

# Increase retries for unreliable networks
client = BaytClient(api_key="your_api_key", max_retries=5)

# Disable retries (not recommended)
client = BaytClient(api_key="your_api_key", max_retries=0)
The SDK retries on:
  • 429 (Rate Limit) - Respects Retry-After header
  • 5xx (Server Errors) - Uses exponential backoff
The SDK does NOT retry on:
  • 4xx (Client Errors) - Except 429
  • Network Errors

Manual Retry Logic

Implement custom retry logic for specific operations:
import time
from baytos.claro import BaytClient, BaytAPIError

def get_prompt_with_retry(client, package_name, max_attempts=3):
    """Get prompt with manual retry logic"""

    for attempt in range(max_attempts):
        try:
            return client.get_prompt(package_name)

        except BaytAPIError as e:
            if attempt == max_attempts - 1:
                # Last attempt - raise the error
                raise

            # Wait before retrying (exponential backoff)
            wait_time = 2 ** attempt
            print(f"Error: {e}")
            print(f"Retrying in {wait_time} seconds... (attempt {attempt + 1}/{max_attempts})")
            time.sleep(wait_time)

# Usage
client = BaytClient(api_key="...")
prompt = get_prompt_with_retry(client, "@workspace/test:v1")

Retry with Decorators

Use a decorator for reusable retry logic:
import time
from functools import wraps
from baytos.claro import BaytAPIError

def retry_on_error(max_attempts=3, delay=1):
    """Decorator to retry on BaytAPIError"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except BaytAPIError as e:
                    if attempt == max_attempts - 1:
                        raise
                    wait_time = delay * (2 ** attempt)
                    time.sleep(wait_time)
            return None
        return wrapper
    return decorator

# Usage
@retry_on_error(max_attempts=3, delay=1)
def fetch_prompt(client, package_name):
    return client.get_prompt(package_name)

client = BaytClient(api_key="...")
prompt = fetch_prompt(client, "@workspace/test:v1")

Graceful Degradation

Provide fallbacks when operations fail:
from baytos.claro import BaytClient, BaytNotFoundError

def get_prompt_with_fallback(client, primary_package, fallback_package=None):
    """Try primary prompt, fall back to alternative if not found"""

    try:
        return client.get_prompt(primary_package)

    except BaytNotFoundError:
        if fallback_package:
            print(f"Primary prompt not found, using fallback: {fallback_package}")
            try:
                return client.get_prompt(fallback_package)
            except BaytNotFoundError:
                print("Fallback prompt also not found")
                raise

        raise

# Usage
client = BaytClient(api_key="...")
prompt = get_prompt_with_fallback(
    client,
    "@workspace/custom-support:v2",
    fallback_package="@workspace/generic-support:v1"
)

Logging Errors

Integrate with Python’s logging system:
import logging
from baytos.claro import BaytClient, BaytAPIError

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

def fetch_prompt_safely(package_name):
    """Fetch prompt with comprehensive logging"""
    client = BaytClient(api_key="...")

    try:
        logger.info(f"Fetching prompt: {package_name}")
        prompt = client.get_prompt(package_name)
        logger.info(f"Successfully fetched: {prompt.title}")
        return prompt

    except BaytAPIError as e:
        logger.error(f"Failed to fetch prompt {package_name}: {e}")
        raise

# Usage
try:
    prompt = fetch_prompt_safely("@workspace/test:v1")
except BaytAPIError:
    # Error already logged
    pass

Error Context

Provide helpful error messages to users:
from baytos.claro import (
    BaytClient,
    BaytAuthError,
    BaytNotFoundError,
    BaytRateLimitError,
    BaytAPIError
)

def get_user_friendly_error(error):
    """Convert SDK errors to user-friendly messages"""

    if isinstance(error, BaytAuthError):
        return (
            "Authentication failed. Please check your API key. "
            "You can generate a new key at: "
            "https://claro.baytos.ai"
        )

    elif isinstance(error, BaytNotFoundError):
        return (
            "The requested prompt was not found. "
            "Please verify the package name and version."
        )

    elif isinstance(error, BaytRateLimitError):
        return (
            "You've made too many requests. "
            "Please wait a few minutes before trying again."
        )

    elif isinstance(error, BaytAPIError):
        return (
            "An error occurred while communicating with Claro. "
            "Please try again later."
        )

    else:
        return f"An unexpected error occurred: {error}"

# Usage
client = BaytClient(api_key="...")

try:
    prompt = client.get_prompt("@workspace/test:v1")
except Exception as e:
    error_message = get_user_friendly_error(e)
    print(error_message)

Complete Example

#!/usr/bin/env python3
"""
Robust error handling example
"""

import os
import sys
import logging
import time
from baytos.claro import (
    BaytClient,
    BaytAuthError,
    BaytNotFoundError,
    BaytRateLimitError,
    BaytValidationError,
    BaytAPIError
)

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

def fetch_prompt_robust(package_name, max_retries=3):
    """Fetch prompt with comprehensive error handling"""

    client = BaytClient(api_key=os.getenv("BAYT_API_KEY"))

    for attempt in range(max_retries):
        try:
            logger.info(f"Fetching prompt: {package_name} (attempt {attempt + 1}/{max_retries})")
            prompt = client.get_prompt(package_name)
            logger.info(f"Successfully fetched: {prompt.title}")
            return prompt

        except BaytAuthError as e:
            logger.error(f"Authentication failed: {e}")
            logger.error("Please check your BAYT_API_KEY environment variable")
            sys.exit(1)  # Don't retry auth errors

        except BaytNotFoundError as e:
            logger.error(f"Prompt not found: {e}")
            logger.error(f"Package name: {package_name}")
            sys.exit(1)  # Don't retry not found errors

        except BaytValidationError as e:
            logger.error(f"Invalid request: {e}")
            sys.exit(1)  # Don't retry validation errors

        except BaytRateLimitError as e:
            if attempt < max_retries - 1:
                wait_time = 60 * (attempt + 1)
                logger.warning(f"Rate limited: {e}")
                logger.warning(f"Waiting {wait_time} seconds before retry...")
                time.sleep(wait_time)
            else:
                logger.error("Rate limit exceeded and max retries exhausted")
                raise

        except BaytAPIError as e:
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt
                logger.warning(f"API error: {e}")
                logger.warning(f"Retrying in {wait_time} seconds...")
                time.sleep(wait_time)
            else:
                logger.error(f"API error after {max_retries} attempts: {e}")
                raise

        except Exception as e:
            logger.error(f"Unexpected error: {e}")
            raise

    return None

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python error_handling_example.py <package_name>")
        sys.exit(1)

    package_name = sys.argv[1]

    try:
        prompt = fetch_prompt_robust(package_name)
        if prompt:
            print(f"\nPrompt: {prompt.title}")
            print(f"Version: {prompt.version}")
            print(f"\nContent:\n{prompt.generator[:200]}...")

    except Exception as e:
        logger.error(f"Failed to fetch prompt: {e}")
        sys.exit(1)

Best Practices

Order exception handlers from most specific to most general:
try:
    prompt = client.get_prompt("@workspace/test:v1")

# ✅ Good: Specific first
except BaytNotFoundError:
    print("Not found")
except BaytAuthError:
    print("Auth error")
except BaytAPIError:
    print("Other API error")

# ❌ Bad: General first (specific handlers never reached)
except BaytAPIError:
    print("API error")
except BaytNotFoundError:
    print("Not found")  # Never reached!
Only retry on transient errors:
# ✅ Good: Retry on transient errors
if isinstance(e, (BaytRateLimitError, BaytAPIError)):
    retry()

# ❌ Bad: Retry on auth errors (will always fail)
if isinstance(e, BaytAuthError):
    retry()  # Pointless - bad key won't become valid
Always log errors with context:
import logging

logger = logging.getLogger(__name__)

try:
    prompt = client.get_prompt(package_name)
except BaytAPIError as e:
    logger.error(
        f"Failed to fetch prompt",
        extra={
            'package_name': package_name,
            'error': str(e),
            'error_type': type(e).__name__
        }
    )
    raise
Don’t expose technical errors to end users:
# ✅ Good: User-friendly message
try:
    prompt = client.get_prompt(pkg)
except BaytAuthError:
    print("We couldn't verify your account. Please check your settings.")

# ❌ Bad: Technical error message
except BaytAuthError as e:
    print(f"BaytAuthError: {e}")  # Confusing for users

Next Steps

Advanced Features

Explore rate limiting and performance optimization

Client Configuration

Configure retries and timeouts

API Reference

Complete exception documentation

Quickstart

Review basic usage patterns