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.
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.
Exception |
Trigger Condition |
Key Attributes |
|---|---|---|
|
General API communication errors |
|
|
GraphQL query too complex |
|
|
Too many mutations per minute |
|
|
Item pagination failures |
|
|
Malformed GraphQL queries |
|
Exception Details
MondayAPIError
- class MondayAPIError(message, json=None)[source]
Bases:
ExceptionException raised when an error occurs during API communication with monday.com.
- message
Explanation of the error.
- json
JSON data returned by the API, if available.
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:
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
- class ComplexityLimitExceeded(message, reset_in, json=None)[source]
Bases:
ExceptionException raised when the complexity limit is exceeded.
- message
Explanation of the error.
- reset_in
Time in seconds until the complexity limit is reset.
- json
JSON data returned by the API, if available.
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:
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
- class MutationLimitExceeded(message, reset_in, json=None)[source]
Bases:
ExceptionException raised when the mutation per minute limit is exceeded.
- message
Explanation of the error.
- reset_in
Time in seconds until the rate limit is reset.
- json
JSON data returned by the API, if available.
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:
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
- class PaginationError(message, json=None)[source]
Bases:
ExceptionException raised when item pagination fails.
- message
Explanation of the error.
- json
JSON data returned by the API, if available.
When it occurs: - Invalid pagination cursors - Attempting to paginate beyond available data - Corrupted pagination state during large data retrievals
Example usage:
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
- class QueryFormatError(message, json=None)[source]
Bases:
ExceptionException raised when a query is improperly formatted.
- message
Explanation of the error.
- json
JSON data returned by the API, if available.
When it occurs: - Malformed GraphQL query syntax - Invalid field names or structures - Incorrect query parameters or arguments
Example usage:
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:
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:
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:
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:
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:
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:
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:
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:
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:
# 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:
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:
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:
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'
)
See also
Usage - Basic usage examples and patterns
Configuration - Configuration options including timeouts and retries
MondayClient - MondayClient API reference