Skip to main content
This guide demonstrates robust error handling patterns for the Claro SDK. Proper error handling ensures your application remains stable and provides helpful feedback when issues occur.

Prerequisites

pip install baytos-claro
export BAYT_API_KEY="your_api_key_here"

Available Exception Types

The Claro SDK provides specific exception types:
ExceptionWhen RaisedHTTP Status
BaytAuthErrorInvalid or missing API key401
BaytNotFoundErrorResource doesn’t exist404
BaytRateLimitErrorRate limit exceeded429
BaytAPIErrorGeneral API errorVarious

Example 1: Basic Error Handling

Handle the most common errors:
import os
from baytos.claro import BaytClient, BaytNotFoundError, BaytAuthError, BaytAPIError

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

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

except BaytNotFoundError as e:
    print(f"Prompt not found: {e}")
    print("Check the package name and version")

except BaytAuthError as e:
    print(f"Authentication failed: {e}")
    print("Verify your API key is correct")

except BaytAPIError as e:
    print(f"API error occurred: {e}")
    print("Please try again later")

except Exception as e:
    print(f"Unexpected error: {e}")
Prompt not found: Prompt not found: @workspace/my-prompt:v1
Check the package name and version

Example 2: Handle Missing API Key

Validate API key before making requests:
import os
from baytos.claro import BaytClient, BaytAuthError

def get_client():
    """Initialize client with proper error handling"""
    api_key = os.getenv("BAYT_API_KEY")

    if not api_key:
        print("Error: BAYT_API_KEY environment variable not set")
        print("\nTo fix this:")
        print("1. Get your API key from: https://claro.baytos.ai")
        print("2. Set it with: export BAYT_API_KEY='your_api_key_here'")
        exit(1)

    try:
        return BaytClient(api_key=api_key)
    except ValueError as e:
        print(f"Invalid API key format: {e}")
        exit(1)

# Usage
client = get_client()
prompt = client.get_prompt("@workspace/my-prompt:v1")

Example 3: Retry Logic

Automatically retry failed requests:
import os
import time
from baytos.claro import BaytClient, BaytRateLimitError, BaytAPIError

def get_prompt_with_retry(package_name, max_retries=3):
    """Fetch prompt with automatic retry"""
    client = BaytClient(api_key=os.getenv("BAYT_API_KEY"))

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

        except BaytRateLimitError as e:
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt  # Exponential backoff: 1s, 2s, 4s
                print(f"Rate limited. Retrying in {wait_time}s...")
                time.sleep(wait_time)
            else:
                print("Rate limit exceeded after all retries")
                raise

        except BaytAPIError as e:
            if attempt < max_retries - 1:
                print(f"API error. Retry {attempt + 1}/{max_retries}...")
                time.sleep(1)
            else:
                print("Failed after all retries")
                raise

# Usage
try:
    prompt = get_prompt_with_retry("@workspace/my-prompt:v1")
    print(f"Successfully loaded: {prompt.title}")
except Exception as e:
    print(f"Failed to load prompt: {e}")
The SDK already includes automatic retry logic for rate limits. This example shows how to add additional retry logic for other scenarios.

Example 4: Graceful Degradation

Provide fallback behavior when prompts aren’t available:
import os
from baytos.claro import BaytClient, BaytNotFoundError, BaytAPIError

def get_prompt_or_fallback(package_name, fallback_content):
    """Get prompt or use fallback"""
    client = BaytClient(api_key=os.getenv("BAYT_API_KEY"))

    try:
        prompt = client.get_prompt(package_name)
        return prompt.generator

    except BaytNotFoundError:
        print(f"Prompt not found, using fallback")
        return fallback_content

    except BaytAPIError as e:
        print(f"API error, using fallback: {e}")
        return fallback_content

# Usage
fallback = "You are a helpful assistant."
content = get_prompt_or_fallback("@workspace/assistant:v1", fallback)
print(f"Using content: {content[:50]}...")

Example 5: Validate Prompt Before Use

Check that a prompt has the expected structure:
import os
from baytos.claro import BaytClient, BaytNotFoundError

class PromptValidationError(Exception):
    """Raised when prompt doesn't meet requirements"""
    pass

def get_validated_prompt(package_name):
    """Get and validate prompt"""
    client = BaytClient(api_key=os.getenv("BAYT_API_KEY"))

    try:
        prompt = client.get_prompt(package_name)

        # Validate prompt has content
        if not prompt.generator:
            raise PromptValidationError("Prompt has no generator content")

        # Validate minimum length
        if len(prompt.generator) < 10:
            raise PromptValidationError("Prompt content too short")

        return prompt

    except BaytNotFoundError:
        raise PromptValidationError(f"Prompt not found: {package_name}")

# Usage
try:
    prompt = get_validated_prompt("@workspace/my-prompt:v1")
    print("Prompt is valid")
except PromptValidationError as e:
    print(f"Validation failed: {e}")
    exit(1)

Example 6: Handle File Download Errors

Robust error handling for file downloads:
import os
from baytos.claro import BaytClient, BaytNotFoundError, BaytAPIError

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

try:
    # Get prompt
    prompt = client.get_prompt("@workspace/prompt-with-files:v1")

    # Check for files
    if not prompt.has_context():
        print("No files attached to this prompt")
        exit(0)

    files = prompt.get_file_contexts()

    # Download each file
    for file in files:
        try:
            print(f"Downloading {file.file_name}...")
            content = client.download_context_file(file.id)

            # Save file
            with open(file.file_name, 'wb') as f:
                f.write(content)

            print(f"✓ Downloaded successfully ({len(content):,} bytes)")

        except BaytNotFoundError:
            print(f"✗ File not found: {file.file_name}")

        except BaytAPIError as e:
            print(f"✗ Download failed: {e}")

        except IOError as e:
            print(f"✗ Could not save file: {e}")

except BaytNotFoundError as e:
    print(f"Prompt not found: {e}")

except Exception as e:
    print(f"Unexpected error: {e}")

Example 7: Logging Errors

Proper error logging for debugging:
import os
import logging
from baytos.claro import BaytClient, BaytAPIError, BaytNotFoundError

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

def get_prompt_with_logging(package_name):
    """Get prompt with comprehensive logging"""
    client = BaytClient(api_key=os.getenv("BAYT_API_KEY"))

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

    except BaytNotFoundError as e:
        logger.error(
            f"Prompt not found: {package_name}",
            extra={'error': str(e)}
        )
        raise

    except BaytAPIError as e:
        logger.error(
            f"API error while fetching {package_name}",
            extra={'error': str(e), 'error_type': type(e).__name__},
            exc_info=True
        )
        raise

# Usage
try:
    prompt = get_prompt_with_logging("@workspace/my-prompt:v1")
except Exception as e:
    logger.critical("Failed to load prompt", exc_info=True)

Example 8: Custom Error Messages

Provide user-friendly error messages:
import os
from baytos.claro import BaytClient, BaytNotFoundError, BaytAuthError, BaytRateLimitError

def get_user_friendly_error(error):
    """Convert exception to user-friendly message"""
    if isinstance(error, BaytAuthError):
        return (
            "Authentication failed. Please check your API key.\n"
            "Get a new key from: https://claro.baytos.ai"
        )

    if isinstance(error, BaytNotFoundError):
        return (
            "The requested prompt could not be found.\n"
            "Please verify the package name and version."
        )

    if isinstance(error, BaytRateLimitError):
        return (
            "You've made too many requests. Please wait a moment.\n"
            "Rate limits help ensure fair usage for all users."
        )

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

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

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

except Exception as e:
    print(get_user_friendly_error(e))

Example 9: Context Manager Pattern

Use context managers for resource cleanup:
import os
from contextlib import contextmanager
from baytos.claro import BaytClient, BaytAPIError

@contextmanager
def prompt_context(package_name):
    """Context manager for prompt operations"""
    client = BaytClient(api_key=os.getenv("BAYT_API_KEY"))
    prompt = None

    try:
        prompt = client.get_prompt(package_name)
        yield prompt

    except BaytAPIError as e:
        print(f"Error loading prompt: {e}")
        raise

    finally:
        # Cleanup if needed
        if prompt:
            print(f"Finished with prompt: {prompt.title}")

# Usage
try:
    with prompt_context("@workspace/my-prompt:v1") as prompt:
        print(f"Using prompt: {prompt.title}")
        # Do work with prompt
except Exception as e:
    print(f"Failed: {e}")

Example 10: Batch Operations Error Handling

Handle errors when processing multiple prompts:
import os
from baytos.claro import BaytClient, BaytNotFoundError, BaytAPIError

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

package_names = [
    "@workspace/prompt1:v1",
    "@workspace/prompt2:v1",
    "@workspace/nonexistent:v1",  # This will fail
    "@workspace/prompt3:v1"
]

successful = []
failed = []

for package_name in package_names:
    try:
        prompt = client.get_prompt(package_name)
        successful.append(prompt)
        print(f"✓ Loaded: {package_name}")

    except BaytNotFoundError:
        failed.append({'package': package_name, 'error': 'Not found'})
        print(f"✗ Not found: {package_name}")

    except BaytAPIError as e:
        failed.append({'package': package_name, 'error': str(e)})
        print(f"✗ Error: {package_name} - {e}")

print(f"\nSummary: {len(successful)} successful, {len(failed)} failed")

if failed:
    print("\nFailed prompts:")
    for item in failed:
        print(f"  - {item['package']}: {item['error']}")

Example 11: Timeout Handling

Handle timeout scenarios:
import os
import signal
from contextlib import contextmanager
from baytos.claro import BaytClient, BaytAPIError

class TimeoutError(Exception):
    pass

@contextmanager
def timeout(seconds):
    """Context manager for timeout"""
    def signal_handler(signum, frame):
        raise TimeoutError(f"Operation timed out after {seconds}s")

    # Set the signal handler
    signal.signal(signal.SIGALRM, signal_handler)
    signal.alarm(seconds)

    try:
        yield
    finally:
        signal.alarm(0)  # Disable the alarm

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

try:
    with timeout(5):  # 5 second timeout
        prompt = client.get_prompt("@workspace/my-prompt:v1")
        print(f"Loaded: {prompt.title}")

except TimeoutError as e:
    print(f"Request timed out: {e}")

except BaytAPIError as e:
    print(f"API error: {e}")
The timeout example uses Unix signals and won’t work on Windows. For cross-platform timeouts, use threading or async patterns.

Example 12: Comprehensive Error Handler

Production-ready error handling wrapper:
import os
import logging
import time
from functools import wraps
from baytos.claro import (
    BaytClient,
    BaytAuthError,
    BaytNotFoundError,
    BaytRateLimitError,
    BaytAPIError
)

logger = logging.getLogger(__name__)

def with_error_handling(max_retries=3, fallback=None):
    """Decorator for comprehensive error handling"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            last_error = None

            for attempt in range(max_retries):
                try:
                    return func(*args, **kwargs)

                except BaytAuthError as e:
                    logger.error(f"Authentication failed: {e}")
                    raise  # Don't retry auth errors

                except BaytNotFoundError as e:
                    logger.error(f"Resource not found: {e}")
                    raise  # Don't retry not found errors

                except BaytRateLimitError as e:
                    if attempt < max_retries - 1:
                        wait_time = 2 ** attempt
                        logger.warning(f"Rate limited. Retrying in {wait_time}s...")
                        time.sleep(wait_time)
                        last_error = e
                        continue
                    raise

                except BaytAPIError as e:
                    if attempt < max_retries - 1:
                        logger.warning(f"API error. Retry {attempt + 1}/{max_retries}")
                        time.sleep(1)
                        last_error = e
                        continue
                    raise

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

            # All retries exhausted
            if fallback is not None:
                logger.warning(f"Using fallback after {max_retries} retries")
                return fallback

            raise last_error

        return wrapper
    return decorator

# Usage
@with_error_handling(max_retries=3)
def get_prompt(package_name):
    client = BaytClient(api_key=os.getenv("BAYT_API_KEY"))
    return client.get_prompt(package_name)

try:
    prompt = get_prompt("@workspace/my-prompt:v1")
    print(f"Loaded: {prompt.title}")
except Exception as e:
    print(f"Failed: {e}")

Next Steps