.. This file is part of monday-client. Copyright (C) 2024 Leet Cyber Security monday-client is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. monday-client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with monday-client. If not, see . .. _exceptions: Exception Handling ================== The monday-client library provides comprehensive error handling through custom exceptions that help you understand and respond to different types of API errors. This page covers all available exceptions, when they occur, and how to handle them effectively. .. contents:: Table of Contents :depth: 3 :local: Exception Overview ------------------ All custom exceptions in monday-client inherit from Python's base ``Exception`` class and provide additional context about API errors. They are designed to give you actionable information for debugging and error recovery. .. list-table:: Exception Summary :header-rows: 1 :widths: 25 25 50 * - Exception - Trigger Condition - Key Attributes * - :exc:`MondayAPIError` - General API communication errors - ``json`` (API response data) * - :exc:`ComplexityLimitExceeded` - GraphQL query too complex - ``reset_in``, ``json`` * - :exc:`MutationLimitExceeded` - Too many mutations per minute - ``reset_in``, ``json`` * - :exc:`PaginationError` - Item pagination failures - ``json`` (pagination context) * - :exc:`QueryFormatError` - Malformed GraphQL queries - ``json`` (format details) Exception Details ----------------- MondayAPIError ~~~~~~~~~~~~~~ .. autoclass:: monday.exceptions.MondayAPIError :members: :show-inheritance: :exclude-members: json **When it occurs:** - Network connectivity issues - Invalid API keys or authentication failures - Server-side errors (5xx responses) - Malformed requests that don't fit other specific categories **Example usage:** .. code-block:: python import asyncio from monday import MondayClient, MondayAPIError async def handle_api_errors(): client = MondayClient(api_key='your_api_key') try: boards = await client.boards.query(board_ids=[123456789]) except MondayAPIError as e: print(f'API Error: {e}') # Access additional error context if e.json: print(f'Error details: {e.json}') # Check for specific error types if 'errors' in e.json: for error in e.json['errors']: print(f'- {error.get("message", "Unknown error")}') asyncio.run(handle_api_errors()) ComplexityLimitExceeded ~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: monday.exceptions.ComplexityLimitExceeded :members: :show-inheritance: :exclude-members: json, reset_in **When it occurs:** - GraphQL query requests too much data in a single call - Deeply nested queries with many relationships - Queries that would consume excessive server resources **Understanding complexity limits:** Monday.com limits the computational complexity of GraphQL queries to ensure fair usage. Complex queries with many nested fields or large result sets can exceed these limits. **Example usage:** .. code-block:: python import asyncio from monday import MondayClient, ComplexityLimitExceeded async def handle_complexity_limits(): client = MondayClient(api_key='your_api_key') try: # This might be too complex if requesting many boards with full details boards = await client.boards.query( board_ids=list(range(1000000, 1000100)), # 100 boards fields='id name description owners { id name email } groups { id title color items { id name column_values { id text } } }' ) except ComplexityLimitExceeded as e: print(f'Query too complex: {e}') print(f'Retry in {e.reset_in} seconds') # The client automatically handles retries, but you can implement custom logic await asyncio.sleep(e.reset_in) # Try a simpler query boards = await client.boards.query( board_ids=[1000000], # Just one board fields='id name description' # Fewer fields ) asyncio.run(handle_complexity_limits()) MutationLimitExceeded ~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: monday.exceptions.MutationLimitExceeded :members: :show-inheritance: :exclude-members: json, reset_in **When it occurs:** - Too many create, update, or delete operations per minute - Exceeding monday.com's mutation rate limits - Bulk operations that happen too quickly **Rate limit details:** Monday.com enforces rate limits on mutations (data-changing operations) to prevent abuse and ensure system stability. The exact limits depend on your plan and current usage. **Example usage:** .. code-block:: python import asyncio from monday import MondayClient, MutationLimitExceeded from monday.types import TextInput async def handle_mutation_limits(): client = MondayClient(api_key='your_api_key') items_to_update = [123456789, 123456790, 123456791] for item_id in items_to_update: try: await client.items.change_column_values( item_id=item_id, column_values=[TextInput('text', f'Updated item {item_id}')] ) except MutationLimitExceeded as e: print(f'Rate limit exceeded: {e}') print(f'Waiting {e.reset_in} seconds before retrying...') # Wait for rate limit to reset await asyncio.sleep(e.reset_in) # Retry the operation await client.items.change_column_values( item_id=item_id, column_values=[TextInput('text', f'Updated item {item_id}')] ) asyncio.run(handle_mutation_limits()) PaginationError ~~~~~~~~~~~~~~~ .. autoclass:: monday.exceptions.PaginationError :members: :show-inheritance: :exclude-members: json **When it occurs:** - Invalid pagination cursors - Attempting to paginate beyond available data - Corrupted pagination state during large data retrievals **Example usage:** .. code-block:: python import asyncio from monday import MondayClient, PaginationError async def handle_pagination_errors(): client = MondayClient(api_key='your_api_key') try: # Get items with pagination item_lists = await client.boards.get_items( board_ids=[123456789], limit=50 ) for item_list in item_lists: print(f'Board {item_list.board_id}: {len(item_list.items)} items') except PaginationError as e: print(f'Pagination failed: {e}') # Try without pagination for smaller datasets item_lists = await client.boards.get_items( board_ids=[123456789], limit=10 # Smaller limit ) asyncio.run(handle_pagination_errors()) QueryFormatError ~~~~~~~~~~~~~~~~ .. autoclass:: monday.exceptions.QueryFormatError :members: :show-inheritance: :exclude-members: json **When it occurs:** - Malformed GraphQL query syntax - Invalid field names or structures - Incorrect query parameters or arguments **Example usage:** .. code-block:: python import asyncio from monday import MondayClient, QueryFormatError async def handle_query_format_errors(): client = MondayClient(api_key='your_api_key') try: # This might cause a format error if fields are invalid boards = await client.boards.query( board_ids=[123456789], fields='invalid_field { also_invalid }' # Bad field names ) except QueryFormatError as e: print(f'Query format error: {e}') if e.json and 'errors' in e.json: for error in e.json['errors']: print(f'GraphQL Error: {error.get("message")}') # Use valid fields instead boards = await client.boards.query( board_ids=[123456789], fields='id name state' # Valid fields ) asyncio.run(handle_query_format_errors()) Best Practices -------------- General Error Handling Strategy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #. **Always use try-catch blocks** for API operations: .. code-block:: python from monday import MondayClient, MondayAPIError async def robust_api_call(): client = MondayClient(api_key='your_api_key') try: result = await client.boards.query(board_ids=[123456789]) return result except MondayAPIError as e: # Log the error for debugging print(f'API call failed: {e}') # Return None or empty list instead of crashing return [] #. **Handle specific exceptions differently**: .. code-block:: python from monday import ( MondayClient, MondayAPIError, ComplexityLimitExceeded, MutationLimitExceeded ) async def comprehensive_error_handling(): client = MondayClient(api_key='your_api_key') try: boards = await client.boards.query(board_ids=[123456789]) except ComplexityLimitExceeded as e: # Simplify the query print(f'Query too complex, simplifying...') boards = await client.boards.query( board_ids=[123456789], fields='id name' ) except MutationLimitExceeded as e: # Wait and retry print(f'Rate limited, waiting {e.reset_in} seconds...') await asyncio.sleep(e.reset_in) boards = await client.boards.query(board_ids=[123456789]) except MondayAPIError as e: # General error handling print(f'API error: {e}') boards = [] Rate Limiting and Retries ~~~~~~~~~~~~~~~~~~~~~~~~~ The monday-client automatically handles rate limiting with built-in retry logic, but you can implement additional strategies: .. code-block:: python import asyncio from monday import MondayClient, ComplexityLimitExceeded, MutationLimitExceeded async def retry_with_backoff(client, max_retries=3): """Retry an operation with exponential backoff.""" for attempt in range(max_retries): try: return await client.items.create( board_id=123456789, item_name='New Item' ) except (ComplexityLimitExceeded, MutationLimitExceeded) as e: if attempt == max_retries - 1: raise # Re-raise on final attempt wait_time = e.reset_in if hasattr(e, 'reset_in') else (2 ** attempt) print(f'Attempt {attempt + 1} failed, waiting {wait_time} seconds...') await asyncio.sleep(wait_time) async def main(): client = MondayClient(api_key='your_api_key') # Retry with backoff new_item = await retry_with_backoff(client) asyncio.run(main()) Query Optimization ~~~~~~~~~~~~~~~~~~ To avoid ``ComplexityLimitExceeded`` errors: .. code-block:: python async def main(): # Too complex - requests everything at once try: boards = await client.boards.query( board_ids=[987654321, 876543210, 765432109, 654321098, 543210987], fields='id name description owners { id name email } groups { id title color items { id name column_values { id text } subitems { id name } } }' ) except ComplexityLimitExceeded: pass # Better - request fewer boards and simpler fields boards = await client.boards.query( board_ids=[987654321, 876543210, 765432109], # Fewer boards fields='id name description' # Essential fields only ) main() Logging and Debugging ~~~~~~~~~~~~~~~~~~~~~ Enable detailed logging to debug exceptions: .. code-block:: python import logging from monday import MondayClient, MondayAPIError # Enable debug logging logging.basicConfig(level=logging.DEBUG) monday_logger = logging.getLogger('monday') monday_logger.setLevel(logging.DEBUG) # Add a handler if none exists if not monday_logger.handlers: handler = logging.StreamHandler() formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) handler.setFormatter(formatter) monday_logger.addHandler(handler) client = MondayClient(api_key='your_api_key') async def main(): return await client.boards.query(board_ids=[123456789]) try: boards = asyncio.run(main()) except MondayAPIError as e: # Detailed error information will be logged automatically print(f'Operation failed: {e}') Common Error Scenarios ---------------------- Authentication Issues ~~~~~~~~~~~~~~~~~~~~~ **Symptoms:** - ``MondayAPIError`` with authentication-related messages - HTTP 401 Unauthorized responses **Solutions:** .. code-block:: python from monday import MondayClient, MondayAPIError async def check_authentication(): try: client = MondayClient(api_key='your_api_key') # Simple query to test authentication boards = await client.boards.query(board_ids=[123456789], fields='id') except MondayAPIError as e: if 'unauthorized' in str(e).lower(): print('Authentication failed. Check your API key.') print('Get your API key from: https://monday.com/developers/api') else: print(f'Other API error: {e}') Network Issues ~~~~~~~~~~~~~~ **Symptoms:** - ``MondayAPIError`` with network-related messages - Timeouts or connection errors **Solutions:** .. code-block:: python import aiohttp from monday import MondayClient, MondayAPIError, Config async def handle_network_issues(): # Configure longer timeout for slow networks config = Config( api_key='your_api_key', timeout=60 # 60 second timeout instead of default 30 ) client = MondayClient(config) try: boards = await client.boards.query(board_ids=[123456789]) except MondayAPIError as e: if 'timeout' in str(e).lower(): print('Request timed out. Try again or check your network.') elif 'connection' in str(e).lower(): print('Connection failed. Check your internet connection.') else: raise Invalid Data Access ~~~~~~~~~~~~~~~~~~~ **Symptoms:** - ``MondayAPIError`` when accessing non-existent boards/items - Permission-related errors **Solutions:** .. code-block:: python from monday import MondayClient, MondayAPIError async def safe_data_access(): client = MondayClient(api_key='your_api_key') try: boards = await client.boards.query(board_ids=[999999999]) # Non-existent board except MondayAPIError as e: if 'not found' in str(e).lower(): print('Board not found or no access permission') return [] elif 'permission' in str(e).lower(): print('Insufficient permissions to access this board') return [] else: raise # Alternative: Check if boards exist first async def check_board_access(): client = MondayClient(api_key='your_api_key') try: # Get all accessible boards first all_boards = await client.boards.query(board_ids=[], fields='id name') accessible_ids = [board.id for board in all_boards] # Only query boards you have access to target_ids = [123456789, 987654321] valid_ids = [id for id in target_ids if str(id) in accessible_ids] if valid_ids: boards = await client.boards.query(board_ids=valid_ids) return boards else: print('No accessible boards found') return [] except MondayAPIError as e: print(f'Error checking board access: {e}') return [] Troubleshooting Guide --------------------- Exception Not Being Caught ~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Problem:** Exceptions are not being caught by your try-catch blocks. **Solution:** Make sure you're importing the correct exceptions: .. code-block:: python # Correct - import specific exceptions from monday.exceptions import MondayAPIError, ComplexityLimitExceeded async def example_function(): # Incorrect - won't catch monday-client exceptions try: result = await client.boards.query(board_ids=[123]) except Exception as e: # Too generic pass # Correct - catch specific exceptions try: result = await client.boards.query(board_ids=[123]) except MondayAPIError as e: print(f'Monday API error: {e}') except Exception as e: # Catch-all for unexpected errors print(f'Unexpected error: {e}') Unclear Error Messages ~~~~~~~~~~~~~~~~~~~~~~ **Problem:** Error messages don't provide enough context. **Solution:** Access the ``json`` attribute for detailed error information: .. code-block:: python from monday import MondayClient, MondayAPIError import json async def debug_errors(): try: boards = await client.boards.query(board_ids=[123456789]) except MondayAPIError as e: print(f'Error message: {e}') if e.json: # Pretty print the full error context print('Full error details:') print(json.dumps(e.json, indent=2)) # Extract specific error information if 'errors' in e.json: for error in e.json['errors']: print(f'GraphQL Error: {error.get("message")}') if 'path' in error: print(f'Error path: {error["path"]}') Frequent Rate Limiting ~~~~~~~~~~~~~~~~~~~~~~ **Problem:** Constantly hitting rate limits. **Solutions:** #. **Reduce request frequency:** .. code-block:: python import asyncio from monday import MondayClient async def batch_operations_with_delay(): client = MondayClient(api_key='your_api_key') items_to_update = [123, 456, 789, 101112] for i, item_id in enumerate(items_to_update): await client.items.change_column_values( item_id=item_id, column_values=[TextInput('text', f'Update {i}')] ) # Add delay between operations if i < len(items_to_update) - 1: await asyncio.sleep(1) # 1 second delay #. **Batch operations when possible:** .. code-block:: python async def batch_example(): # Individual requests (more likely to hit limits) for item_id in [123, 456, 789]: await client.items.change_column_values( item_id=item_id, column_values=[TextInput('text', 'Updated')] ) # Fewer, larger requests all_items = await client.items.query( item_ids=[123, 456, 789], fields='id name' ) .. seealso:: - :doc:`usage` - Basic usage examples and patterns - :doc:`configuration` - Configuration options including timeouts and retries - :doc:`monday_client` - MondayClient API reference