Error Handling
Building robust applications requires proper error handling. The TABStack Python SDK provides specific exception classes for different error scenarios.
Error Class Hierarchy
TABStackError (base class)
├── BadRequestError (400)
├── UnauthorizedError (401)
├── InvalidURLError (422)
├── ServerError (500)
├── ServiceUnavailableError (503)
└── APIError (generic, with status code)
Importing Error Classes
from tabstack import (
TABStack,
TABStackError,
BadRequestError,
UnauthorizedError,
InvalidURLError,
ServerError,
ServiceUnavailableError,
APIError
)
Error Classes Reference
TABStackError
Base error class for all SDK errors.
Attributes:
message: str- Error messagestatus_code: Optional[int]- HTTP status code (if applicable)
BadRequestError (400)
Raised when the request is malformed or invalid.
Common causes:
- Missing required parameters
- Invalid JSON schema format
- Malformed request body
UnauthorizedError (401)
Raised when authentication fails.
Common causes:
- Invalid API key
- Missing API key
- Expired API key
InvalidURLError (422)
Raised when the provided URL is invalid or inaccessible.
Common causes:
- Malformed URL format
- URL points to private/internal resources
- URL is unreachable
ServerError (500)
Raised when the server encounters an internal error.
Common causes:
- Failed to fetch the URL
- Page content too large
- Failed to generate/extract data
ServiceUnavailableError (503)
Raised when the service is temporarily unavailable.
Common causes:
- Server maintenance
- Temporary overload
- Rate limiting
APIError
Generic API error with HTTP status code.
Attributes:
status_code: int- HTTP status codemessage: str- Error message
Basic Error Handling
Simple Try-Except
import asyncio
import os
from tabstack import TABStack, TABStackError
async def main():
async with TABStack(api_key=os.getenv('TABSTACK_API_KEY')) as tabs:
try:
result = await tabs.extract.markdown('https://example.com')
print(result.content)
except TABStackError as error:
print(f'API error: {error.message}')
except Exception as error:
print(f'Unexpected error: {error}')
asyncio.run(main())
Handling Specific Error Types
import asyncio
import os
from tabstack import (
TABStack,
UnauthorizedError,
InvalidURLError,
ServerError,
TABStackError
)
async def extract_with_error_handling(url: str):
async with TABStack(api_key=os.getenv('TABSTACK_API_KEY')) as tabs:
try:
result = await tabs.extract.markdown(url)
return result
except UnauthorizedError:
print('Authentication failed. Please check your API key.')
except InvalidURLError as error:
print(f'Invalid or inaccessible URL: {url}')
except ServerError as error:
print(f'Server error occurred: {error.message}')
# Implement retry logic
except TABStackError as error:
print(f'API error: {error.message}')
except Exception as error:
print(f'Unexpected error: {error}')
raise
asyncio.run(extract_with_error_handling('https://example.com'))
Advanced Error Handling
Retry Logic with Exponential Backoff
import asyncio
from tabstack import TABStack, ServerError, ServiceUnavailableError
async def extract_with_retry(url: str, max_retries: int = 3, base_delay: float = 1.0):
"""Extract markdown with retry logic for server errors."""
last_error = None
for attempt in range(max_retries):
try:
async with TABStack(api_key=os.getenv('TABSTACK_API_KEY')) as tabs:
result = await tabs.extract.markdown(url)
return result
except (ServerError, ServiceUnavailableError) as error:
last_error = error
if attempt < max_retries - 1:
# Exponential backoff: 1s, 2s, 4s, etc.
delay = base_delay * (2 ** attempt)
print(f"Attempt {attempt + 1} failed. Retrying in {delay}s...")
await asyncio.sleep(delay)
continue
except Exception as error:
# Don't retry other errors
raise
raise Exception(f"Failed after {max_retries} attempts: {last_error}")
# Usage
async def main():
try:
result = await extract_with_retry('https://example.com')
print('Success:', result.content[:100])
except Exception as error:
print(f'Failed: {error}')
asyncio.run(main())
Batch Processing with Error Tracking
import asyncio
from typing import List, Dict, Any
from dataclasses import dataclass
from tabstack import TABStack, TABStackError
@dataclass
class BatchResult:
url: str
success: bool
data: Any = None
error: str = None
async def batch_extract_with_error_handling(
urls: List[str],
schema: dict
) -> List[BatchResult]:
"""Extract from multiple URLs with error tracking."""
results = []
async with TABStack(api_key=os.getenv('TABSTACK_API_KEY')) as tabs:
for url in urls:
try:
result = await tabs.extract.json(url, schema)
results.append(BatchResult(
url=url,
success=True,
data=result.data
))
print(f"✅ Success: {url}")
except TABStackError as error:
results.append(BatchResult(
url=url,
success=False,
error=error.message
))
print(f"❌ Failed: {url} - {error.message}")
except Exception as error:
results.append(BatchResult(
url=url,
success=False,
error=str(error)
))
print(f"❌ Failed: {url} - {error}")
return results
# Usage
async def main():
urls = [
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3'
]
schema = {"type": "object", "properties": {"title": {"type": "string"}}}
results = await batch_extract_with_error_handling(urls, schema)
successful = [r for r in results if r.success]
failed = [r for r in results if not r.success]
print(f"\nBatch Complete: {len(successful)} succeeded, {len(failed)} failed")
if failed:
print('\nFailed URLs:')
for result in failed:
print(f" - {result.url}: {result.error}")
asyncio.run(main())
Error Logging
import asyncio
import logging
from datetime import datetime
from tabstack import TABStack, TABStackError, APIError
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger('tabstack_app')
async def logged_extract(url: str):
"""Extract with comprehensive error logging."""
async with TABStack(api_key=os.getenv('TABSTACK_API_KEY')) as tabs:
try:
logger.info(f"Starting extraction from {url}")
result = await tabs.extract.markdown(url)
logger.info(f"Successfully extracted {len(result.content)} characters")
return result
except TABStackError as error:
logger.error(
f"API error during extraction",
extra={
'url': url,
'error_type': type(error).__name__,
'error_message': error.message,
'status_code': getattr(error, 'status_code', None)
}
)
raise
except Exception as error:
logger.exception(f"Unexpected error during extraction from {url}")
raise
# Usage
asyncio.run(logged_extract('https://example.com'))
Automate Error Handling
async def automate_with_error_handling(task: str, url: str):
"""Execute automation with proper error handling."""
async with TABStack(api_key=os.getenv('TABSTACK_API_KEY')) as tabs:
try:
async for event in tabs.automate.execute(task=task, url=url):
# Handle error events within the stream
if event.type == 'error':
error = event.data.get('error')
print(f'Automation error: {error}')
raise Exception(f'Automation failed: {error}')
elif event.type == 'task:aborted':
reason = event.data.get('reason')
print(f'Task aborted: {reason}')
raise Exception(f'Task aborted: {reason}')
elif event.type == 'task:completed':
result = event.data.get('finalAnswer')
print(f'Success: {result}')
return result
except TABStackError as error:
print(f'API error during automation: {error.message}')
raise
except Exception as error:
print(f'Unexpected error: {error}')
raise
# Usage
asyncio.run(automate_with_error_handling(
'Extract the top 5 articles',
'https://news.example.com'
))
Best Practices
1. Always Use Try-Except
# ✅ Good
try:
result = await tabs.extract.markdown(url)
except TABStackError as error:
# Handle error
pass
2. Handle Specific Errors First
# ✅ Good: Specific to generic
try:
result = await tabs.extract.markdown(url)
except UnauthorizedError:
# Handle auth error
pass
except InvalidURLError:
# Handle URL error
pass
except TABStackError:
# Handle other API errors
pass
except Exception:
# Handle unexpected errors
pass
3. Implement Retry for Transient Errors
# ✅ Good: Retry server errors
try:
result = await tabs.extract.markdown(url)
except (ServerError, ServiceUnavailableError):
# Retry with backoff
pass
except UnauthorizedError:
# Don't retry - fix the issue
raise
4. Use Context Managers
# ✅ Good: Automatic cleanup even on errors
async with TABStack(api_key=api_key) as tabs:
result = await tabs.extract.markdown(url)
Common Error Scenarios
Invalid API Key
try:
async with TABStack(api_key='invalid-key') as tabs:
result = await tabs.extract.markdown(url)
except UnauthorizedError:
print('Please set a valid API key in TABSTACK_API_KEY environment variable')
URL Cannot Be Accessed
try:
result = await tabs.extract.markdown('https://localhost:3000')
except InvalidURLError:
print('Cannot access private URLs like localhost')
Schema Mismatch
try:
result = await tabs.extract.json(url, incompatible_schema)
except ServerError as error:
if 'failed to generate' in error.message.lower():
print('Schema does not match page content. Try generating a schema first.')
Next Steps
- Quickstart: Get started with the SDK
- Extract Features: Learn about data extraction
- Generate Features: Discover AI transformations
- Automate Features: Execute browser automation