CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-azure-data-tables

Microsoft Azure Data Tables Client Library for Python

90

0.96x
Overview
Eval results
Files

error-handling.mddocs/

Error Handling

Comprehensive exception handling with specific error codes, transaction failure management, and detailed error information for robust Azure Tables application development.

Capabilities

Exception Types

Azure Tables library provides specific exception types for different error scenarios with detailed error information.

class TableTransactionError(HttpResponseError):
    """
    Exception raised when a batch transaction operation fails.
    
    Inherits from HttpResponseError and contains detailed information 
    about which operation failed and the specific error that occurred.
    """
    
    def __init__(self, **kwargs: Any) -> None:
        """
        Initialize transaction error.

        Parameters:
        - **kwargs: Keyword arguments passed to HttpResponseError base class
          including message, response, and other error details
        """
    
    @property
    def index(self) -> int:
        """
        Index of the failed operation in the transaction (0-based).
        
        Automatically extracted from error message or defaults to 0
        if index cannot be determined.
        """
    
    @property
    def error_code(self) -> TableErrorCode:
        """Specific error code for the failure."""
    
    @property
    def message(self) -> str:
        """Human-readable error message."""
    
    @property
    def additional_info(self) -> Mapping[str, Any]:
        """Additional error information and context."""

class RequestTooLargeError(TableTransactionError):
    """
    Exception for HTTP 413 - Request Entity Too Large errors.
    
    Raised when the request payload exceeds service limits.
    Inherits all properties and methods from TableTransactionError.
    """

Usage Example

from azure.data.tables import TableClient, TableTransactionError, RequestTooLargeError

table_client = TableClient.from_connection_string(conn_str, "orders")

# Handle transaction errors
operations = [
    ("create", {"PartitionKey": "batch", "RowKey": "001", "Name": "Order 1"}),
    ("create", {"PartitionKey": "batch", "RowKey": "002", "Name": "Order 2"}),
    ("update", {"PartitionKey": "batch", "RowKey": "999", "Name": "Non-existent"})
]

try:
    results = table_client.submit_transaction(operations)
except TableTransactionError as e:
    print(f"Transaction failed at operation {e.index}")
    print(f"Error code: {e.error_code}")
    print(f"Error message: {e.message}")
    
    if e.additional_info:
        print(f"Additional details: {e.additional_info}")
    
    # Handle specific error
    if e.error_code == TableErrorCode.RESOURCE_NOT_FOUND:
        print("The entity being updated doesn't exist")

# Handle request size errors  
try:
    large_entity = {"PartitionKey": "big", "RowKey": "001"}
    # Add lots of data that exceeds 1MB limit
    large_entity["BigData"] = "x" * (1024 * 1024 + 1)
    table_client.create_entity(large_entity)
except RequestTooLargeError as e:
    print(f"Entity too large: {e.message}")
    # Split data or reduce entity size

Error Code System

Comprehensive enumeration of error codes for different failure scenarios.

class TableErrorCode(str, Enum):
    """
    Comprehensive error codes for Azure Tables service operations.
    
    Covers authentication, authorization, resource management,
    entity operations, validation, condition checking, and service errors.
    """
    
    # Account and Authentication Errors
    ACCOUNT_ALREADY_EXISTS = "AccountAlreadyExists"
    ACCOUNT_BEING_CREATED = "AccountBeingCreated"
    ACCOUNT_IS_DISABLED = "AccountIsDisabled"
    AUTHENTICATION_FAILED = "AuthenticationFailed"
    AUTHORIZATION_FAILURE = "AuthorizationFailure"
    NO_AUTHENTICATION_INFORMATION = "NoAuthenticationInformation"
    INVALID_AUTHENTICATION_INFO = "InvalidAuthenticationInfo"
    INSUFFICIENT_ACCOUNT_PERMISSIONS = "InsufficientAccountPermissions"
    
    # Condition and Concurrency Errors
    CONDITION_HEADERS_NOT_SUPPORTED = "ConditionHeadersNotSupported"
    CONDITION_NOT_MET = "ConditionNotMet"
    UPDATE_CONDITION_NOT_SATISFIED = "UpdateConditionNotSatisfied"
    MULTIPLE_CONDITION_HEADERS_NOT_SUPPORTED = "MultipleConditionHeadersNotSupported"
    
    # Resource Management Errors
    RESOURCE_NOT_FOUND = "ResourceNotFound"
    RESOURCE_ALREADY_EXISTS = "ResourceAlreadyExists"
    RESOURCE_TYPE_MISMATCH = "ResourceTypeMismatch"
    TABLE_NOT_FOUND = "TableNotFound"
    TABLE_ALREADY_EXISTS = "TableAlreadyExists"
    TABLE_BEING_DELETED = "TableBeingDeleted"
    
    # Entity Operation Errors
    ENTITY_NOT_FOUND = "EntityNotFound"
    ENTITY_ALREADY_EXISTS = "EntityAlreadyExists"
    ENTITY_TOO_LARGE = "EntityTooLarge"
    
    # Property and Data Validation Errors
    DUPLICATE_PROPERTIES_SPECIFIED = "DuplicatePropertiesSpecified"
    PROPERTIES_NEED_VALUE = "PropertiesNeedValue"
    PROPERTY_NAME_INVALID = "PropertyNameInvalid"
    PROPERTY_NAME_TOO_LONG = "PropertyNameTooLong"
    PROPERTY_VALUE_TOO_LARGE = "PropertyValueTooLarge"
    TOO_MANY_PROPERTIES = "TooManyProperties"
    INVALID_VALUE_TYPE = "InvalidValueType"
    INVALID_DUPLICATE_ROW = "InvalidDuplicateRow"
    
    # Request Validation Errors
    INVALID_INPUT = "InvalidInput"
    INVALID_RESOURCE_NAME = "InvalidResourceName"
    INVALID_HEADER_VALUE = "InvalidHeaderValue"
    INVALID_HTTP_VERB = "InvalidHttpVerb"
    INVALID_MD5 = "InvalidMd5"
    INVALID_METADATA = "InvalidMetadata"
    INVALID_QUERY_PARAMETER_VALUE = "InvalidQueryParameterValue"
    INVALID_RANGE = "InvalidRange"
    INVALID_URI = "InvalidUri"
    INVALID_XML_DOCUMENT = "InvalidXmlDocument"
    INVALID_XML_NODE_VALUE = "InvalidXmlNodeValue"
    OUT_OF_RANGE_INPUT = "OutOfRangeInput"
    OUT_OF_RANGE_QUERY_PARAMETER_VALUE = "OutOfRangeQueryParameterValue"
    
    # Request Format and Size Errors
    REQUEST_BODY_TOO_LARGE = "RequestBodyTooLarge"
    REQUEST_URL_FAILED_TO_PARSE = "RequestUrlFailedToParse"
    METADATA_TOO_LARGE = "MetadataTooLarge"
    EMPTY_METADATA_KEY = "EmptyMetadataKey"
    MD5_MISMATCH = "Md5Mismatch"
    
    # Missing Required Elements
    MISSING_CONTENT_LENGTH_HEADER = "MissingContentLengthHeader"
    MISSING_REQUIRED_QUERY_PARAMETER = "MissingRequiredQueryParameter"
    MISSING_REQUIRED_HEADER = "MissingRequiredHeader"
    MISSING_REQUIRED_XML_NODE = "MissingRequiredXmlNode"
    HOST_INFORMATION_NOT_PRESENT = "HostInformationNotPresent"
    
    # Service and Operation Errors
    INTERNAL_ERROR = "InternalError"
    OPERATION_TIMED_OUT = "OperationTimedOut"
    SERVER_BUSY = "ServerBusy"
    METHOD_NOT_ALLOWED = "MethodNotAllowed"
    NOT_IMPLEMENTED = "NotImplemented"
    
    # Unsupported Operations
    UNSUPPORTED_HEADER = "UnsupportedHeader"
    UNSUPPORTED_XML_NODE = "UnsupportedXmlNode"
    UNSUPPORTED_QUERY_PARAMETER = "UnsupportedQueryParameter"
    UNSUPPORTED_HTTP_VERB = "UnsupportedHttpVerb"
    JSON_FORMAT_NOT_SUPPORTED = "JsonFormatNotSupported"
    
    # X-Method Related Errors
    X_METHOD_INCORRECT_COUNT = "XMethodIncorrectCount"
    X_METHOD_INCORRECT_VALUE = "XMethodIncorrectValue"
    X_METHOD_NOT_USING_POST = "XMethodNotUsingPost"

Usage Example

from azure.data.tables import TableClient, TableErrorCode
from azure.core.exceptions import ResourceNotFoundError, ResourceExistsError

table_client = TableClient.from_connection_string(conn_str, "products")

# Handle specific error scenarios
def safe_entity_operations():
    try:
        # Try to get entity
        entity = table_client.get_entity("electronics", "laptop001")
        return entity
        
    except ResourceNotFoundError as e:
        if hasattr(e, 'error_code') and e.error_code == TableErrorCode.ENTITY_NOT_FOUND:
            print("Entity doesn't exist, creating new one")
            new_entity = {
                "PartitionKey": "electronics",
                "RowKey": "laptop001", 
                "Name": "Default Laptop",
                "Price": 999.99
            }
            return table_client.create_entity(new_entity)
        else:
            print(f"Table or other resource not found: {e}")
            raise
            
    except ResourceExistsError as e:
        if hasattr(e, 'error_code') and e.error_code == TableErrorCode.ENTITY_ALREADY_EXISTS:
            print("Entity already exists, updating instead")
            # Handle duplicate creation attempt
            return table_client.update_entity(entity)
        else:
            raise

# Check for authentication issues
def handle_auth_errors():
    try:
        tables = list(table_client.list_entities())
        
    except Exception as e:
        if hasattr(e, 'error_code'):
            if e.error_code == TableErrorCode.AUTHENTICATION_FAILED:
                print("Check your account key or connection string")
            elif e.error_code == TableErrorCode.AUTHORIZATION_FAILURE:
                print("Check your permissions or SAS token scope")
            elif e.error_code == TableErrorCode.INSUFFICIENT_ACCOUNT_PERMISSIONS:
                print("Account needs additional permissions for this operation")
        raise

Common Error Scenarios

Typical error scenarios and recommended handling strategies.

Authentication and Authorization Errors

from azure.data.tables import TableServiceClient
from azure.core.exceptions import ClientAuthenticationError

def handle_auth_scenarios():
    """Handle common authentication scenarios."""
    
    try:
        service_client = TableServiceClient.from_connection_string(
            "DefaultEndpointsProtocol=https;AccountName=test;AccountKey=invalid"
        )
        tables = list(service_client.list_tables())
        
    except ClientAuthenticationError as e:
        print("Authentication failed:")
        
        if "invalid account key" in str(e).lower():
            print("- Check your account key in the connection string")
        elif "account not found" in str(e).lower():
            print("- Verify the account name is correct")
        elif "signature did not match" in str(e).lower():
            print("- Account key may be incorrect or rotated")
        
        # Suggested recovery actions
        print("Recovery suggestions:")
        print("1. Verify connection string in Azure portal")
        print("2. Check if account keys were recently rotated")
        print("3. Ensure account name and key are correctly configured")

Resource Management Errors

from azure.data.tables import TableServiceClient
from azure.core.exceptions import ResourceNotFoundError, ResourceExistsError

def handle_resource_errors():
    """Handle table and resource management errors."""
    
    service_client = TableServiceClient.from_connection_string(conn_str)
    
    # Safe table creation
    def create_table_safely(table_name: str):
        try:
            table_client = service_client.create_table(table_name)
            print(f"Created table: {table_name}")
            return table_client
            
        except ResourceExistsError:
            print(f"Table {table_name} already exists, getting existing client")
            return service_client.get_table_client(table_name)
    
    # Safe table deletion  
    def delete_table_safely(table_name: str):
        try:
            service_client.delete_table(table_name)
            print(f"Deleted table: {table_name}")
            
        except ResourceNotFoundError:
            print(f"Table {table_name} doesn't exist, nothing to delete")
    
    # Table operations with retry
    def robust_table_operation(table_name: str):
        max_retries = 3
        for attempt in range(max_retries):
            try:
                table_client = service_client.get_table_client(table_name)
                entities = list(table_client.list_entities())
                return entities
                
            except ResourceNotFoundError:
                if attempt < max_retries - 1:
                    print(f"Table not found, creating... (attempt {attempt + 1})")
                    create_table_safely(table_name)
                else:
                    raise

Entity Operation Errors

from azure.data.tables import TableClient, UpdateMode
from azure.core.exceptions import ResourceNotFoundError, ResourceExistsError, ResourceModifiedError

def handle_entity_errors():
    """Handle entity-specific error scenarios."""
    
    table_client = TableClient.from_connection_string(conn_str, "customers")
    
    # Safe entity retrieval
    def get_entity_safely(partition_key: str, row_key: str):
        try:
            return table_client.get_entity(partition_key, row_key)
        except ResourceNotFoundError:
            print(f"Entity ({partition_key}, {row_key}) not found")
            return None
    
    # Robust entity creation
    def create_or_update_entity(entity_data):
        try:
            # Try creating first
            result = table_client.create_entity(entity_data)
            print("Entity created successfully")
            return result
            
        except ResourceExistsError:
            print("Entity exists, updating instead")
            try:
                return table_client.update_entity(entity_data, mode=UpdateMode.REPLACE)
            except ResourceNotFoundError:
                # Race condition: entity was deleted between create failure and update
                print("Entity disappeared, retrying create")
                return table_client.create_entity(entity_data)
    
    # Optimistic concurrency handling
    def update_with_concurrency_check(partition_key: str, row_key: str, updates):
        max_retries = 3
        
        for attempt in range(max_retries):
            try:
                # Get current entity
                entity = table_client.get_entity(partition_key, row_key)
                
                # Apply updates
                for key, value in updates.items():
                    entity[key] = value
                
                # Update with concurrency check
                return table_client.update_entity(
                    entity,
                    etag=entity.metadata['etag'],
                    match_condition=MatchConditions.IfNotModified
                )
                
            except ResourceModifiedError:
                if attempt < max_retries - 1:
                    print(f"Concurrency conflict, retrying... (attempt {attempt + 1})")
                    continue
                else:
                    print("Max retries exceeded, giving up")
                    raise
            except ResourceNotFoundError:
                print("Entity was deleted by another process")
                raise

Batch Transaction Error Handling

from azure.data.tables import TableClient, TableTransactionError

def handle_batch_errors():
    """Handle batch transaction error scenarios."""
    
    table_client = TableClient.from_connection_string(conn_str, "orders")
    
    def robust_batch_operation(operations):
        """Execute batch with detailed error handling."""
        
        try:
            results = table_client.submit_transaction(operations)
            print(f"Batch completed successfully: {len(results)} operations")
            return results
            
        except TableTransactionError as e:
            print(f"Batch failed at operation {e.index}")
            failed_operation = operations[e.index]
            
            # Analyze the failed operation
            operation_type, entity_data = failed_operation[:2]
            print(f"Failed operation: {operation_type}")
            print(f"Entity: PK={entity_data.get('PartitionKey')}, RK={entity_data.get('RowKey')}")
            print(f"Error: {e.error_code} - {e.message}")
            
            # Handle specific error types
            if e.error_code == TableErrorCode.ENTITY_ALREADY_EXISTS:
                print("Consider using upsert instead of create")
                
            elif e.error_code == TableErrorCode.ENTITY_NOT_FOUND:
                print("Entity doesn't exist for update/delete operation")
                
            elif e.error_code == TableErrorCode.CONDITION_NOT_MET:
                print("Concurrency condition failed, entity was modified")
            
            # Option: Execute operations individually for partial success
            return execute_operations_individually(operations, e.index)
    
    def execute_operations_individually(operations, failed_index):
        """Execute operations one by one, skipping the failed one."""
        
        results = []
        for i, operation in enumerate(operations):
            if i == failed_index:
                print(f"Skipping failed operation {i}")
                results.append(None)
                continue
                
            try:
                operation_type, entity_data = operation[:2]
                
                if operation_type == "create":
                    result = table_client.create_entity(entity_data)
                elif operation_type == "update":
                    result = table_client.update_entity(entity_data)
                elif operation_type == "upsert":
                    result = table_client.upsert_entity(entity_data)
                elif operation_type == "delete":
                    table_client.delete_entity(entity_data)
                    result = {"status": "deleted"}
                
                results.append(result)
                print(f"Operation {i} completed individually")
                
            except Exception as individual_error:
                print(f"Operation {i} also failed individually: {individual_error}")
                results.append(None)
        
        return results

Error Recovery Patterns

Common patterns for recovering from various error conditions.

Retry with Exponential Backoff

import time
import random
from azure.core.exceptions import ServiceRequestError

def retry_with_backoff(func, max_retries=3, base_delay=1.0):
    """Execute function with exponential backoff retry."""
    
    for attempt in range(max_retries):
        try:
            return func()
            
        except ServiceRequestError as e:
            if attempt == max_retries - 1:
                raise  # Re-raise on final attempt
                
            # Calculate delay with jitter
            delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
            print(f"Attempt {attempt + 1} failed, retrying in {delay:.2f}s")
            time.sleep(delay)

# Usage
def unreliable_operation():
    return table_client.create_entity(entity_data)

result = retry_with_backoff(unreliable_operation)

Circuit Breaker Pattern

from datetime import datetime, timedelta

class CircuitBreaker:
    """Circuit breaker for failing operations."""
    
    def __init__(self, failure_threshold=5, timeout=60):
        self.failure_threshold = failure_threshold
        self.timeout = timeout
        self.failure_count = 0
        self.last_failure_time = None
        self.state = "CLOSED"  # CLOSED, OPEN, HALF_OPEN
    
    def call(self, func):
        if self.state == "OPEN":
            if datetime.now() - self.last_failure_time > timedelta(seconds=self.timeout):
                self.state = "HALF_OPEN"
            else:
                raise Exception("Circuit breaker is OPEN")
        
        try:
            result = func()
            self.on_success()
            return result
        except Exception as e:
            self.on_failure()
            raise
    
    def on_success(self):
        self.failure_count = 0
        self.state = "CLOSED"
    
    def on_failure(self):
        self.failure_count += 1
        self.last_failure_time = datetime.now()
        
        if self.failure_count >= self.failure_threshold:
            self.state = "OPEN"

# Usage
circuit_breaker = CircuitBreaker()

def protected_operation():
    return circuit_breaker.call(lambda: table_client.list_entities())

Install with Tessl CLI

npx tessl i tessl/pypi-azure-data-tables

docs

async-operations.md

batch-operations.md

entity-data-types.md

error-handling.md

index.md

security-access-control.md

service-management.md

table-operations.md

tile.json