Skip to main content

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 message
  • status_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 code
  • message: 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