Overview
Twikit provides a comprehensive set of exception classes for handling errors from the Twitter API. All exceptions inherit from the base TwitterException class and include HTTP status codes and response headers when available.
Exception Hierarchy
TwitterException (base)
├── BadRequest (400)
├── Unauthorized (401)
├── Forbidden (403)
├── NotFound (404)
├── RequestTimeout (408)
├── TooManyRequests (429)
├── ServerError (5xx)
├── CouldNotTweet
│ └── DuplicateTweet (187)
├── TweetNotAvailable
├── InvalidMedia (324)
├── UserNotFound
├── UserUnavailable
├── AccountSuspended
└── AccountLocked
Base Exception
Base class for all Twitter API related exceptions.
class TwitterException(Exception)
Attributes
HTTP response headers from the failed request, if available.
HTTP Status Exceptions
These exceptions correspond to HTTP status codes returned by the Twitter API.
BadRequest
HTTP Status: 400
Raised when the request is malformed or contains invalid parameters.
Common Causes:
- Invalid parameter values
- Missing required parameters
- Malformed request body
- Invalid media IDs
try:
await client.create_tweet('') # Empty text
except BadRequest as e:
print(f"Bad request: {e}")
Unauthorized
HTTP Status: 401
Raised when authentication fails or credentials are invalid.
Common Causes:
- Invalid or expired authentication tokens
- Missing authentication
- Incorrect login credentials
- Session expired
try:
await client.get_user_by_screen_name('example')
except Unauthorized as e:
print("Authentication failed. Please log in again.")
# Re-authenticate
await client.login(username, password)
Forbidden
HTTP Status: 403
Raised when the request is valid but not allowed due to permissions or policy restrictions.
Common Causes:
- Insufficient permissions
- Protected account accessed without permission
- Action blocked by Twitter policy
- Account restrictions
try:
await client.follow_user(user_id)
except Forbidden as e:
print("Action forbidden. You may not have permission.")
NotFound
HTTP Status: 404
Raised when the requested resource does not exist.
Common Causes:
- Tweet has been deleted
- User account deleted or suspended
- Invalid tweet or user ID
- Resource never existed
try:
tweet = await client.get_tweet_by_id('invalid_id')
except NotFound:
print("Tweet not found. It may have been deleted.")
RequestTimeout
HTTP Status: 408
Raised when the request times out.
Common Causes:
- Network connectivity issues
- Server taking too long to respond
- Large data transfers
import asyncio
try:
tweets = await asyncio.wait_for(
client.get_user_tweets(user_id, count=100),
timeout=30
)
except RequestTimeout:
print("Request timed out. Please try again.")
TooManyRequests
HTTP Status: 429
Raised when you exceed the API rate limits.
Common Causes:
- Making too many requests in a short time
- Exceeding hourly or daily limits
- Multiple simultaneous requests
Attributes
Unix timestamp indicating when the rate limit will reset.
import time
from datetime import datetime
try:
tweets = await client.search_tweet('python', 'Latest')
except TooManyRequests as e:
if e.rate_limit_reset:
reset_time = datetime.fromtimestamp(e.rate_limit_reset)
wait_seconds = e.rate_limit_reset - time.time()
print(f"Rate limited. Resets at {reset_time}")
print(f"Waiting {wait_seconds:.0f} seconds...")
await asyncio.sleep(wait_seconds)
# Retry the request
tweets = await client.search_tweet('python', 'Latest')
else:
print("Rate limited. Please try again later.")
ServerError
HTTP Status: 5xx (500, 502, 503, 504)
Raised when Twitter’s servers encounter an error.
Common Causes:
- Twitter server issues
- Service outages
- Internal server errors
- Gateway timeouts
try:
trends = await client.get_trends('trending')
except ServerError as e:
print("Twitter server error. Please try again later.")
Specific Content Exceptions
Raised when a tweet cannot be sent for any reason.
Common Causes:
- Content policy violations
- Spam detection
- Rate limiting on posting
- Account restrictions
try:
await client.create_tweet('My tweet')
except CouldNotTweet as e:
print(f"Could not send tweet: {e}")
Error Code: 187
Inherits from CouldNotTweet. Raised when attempting to post a duplicate tweet.
Common Causes:
- Posting the exact same text as a recent tweet
- Duplicate content within a short time period
try:
await client.create_tweet('Hello World')
await client.create_tweet('Hello World') # Duplicate
except DuplicateTweet:
print("This tweet is a duplicate. Please post something different.")
except CouldNotTweet as e:
print(f"Tweet failed for another reason: {e}")
Raised when a tweet exists but is not available to view.
Common Causes:
- Tweet from protected account
- Tweet hidden by author
- Tweet restricted by age or location
- Violation of terms of service
try:
tweet = await client.get_tweet_by_id(tweet_id)
except TweetNotAvailable:
print("Tweet is not available. It may be protected or restricted.")
except NotFound:
print("Tweet does not exist or has been deleted.")
Error Code: 324
Raised when there’s a problem with media attachments.
Common Causes:
- Invalid media ID
- Media file corrupted
- Media type not supported
- Media already used in another tweet
try:
media_id = await client.upload_media('image.jpg')
await client.create_tweet('Check this out!', media_ids=[media_id])
# Try to reuse the same media
await client.create_tweet('Again!', media_ids=[media_id])
except InvalidMedia:
print("Invalid media. Upload a new media file.")
UserNotFound
Raised when a user account does not exist.
Common Causes:
- User ID or screen name doesn’t exist
- Account was permanently deleted
- Typo in username
try:
user = await client.get_user_by_screen_name('nonexistentuser123456')
except UserNotFound:
print("User not found. Check the username.")
UserUnavailable
Raised when a user account exists but is unavailable.
Common Causes:
- Account temporarily restricted
- Protected account without permission
- Account in limited state
try:
user = await client.get_user_by_id(user_id)
except UserUnavailable:
print("User is unavailable. They may have protected their account.")
except UserNotFound:
print("User does not exist.")
AccountSuspended
Raised when attempting to access or use a suspended account.
Common Causes:
- Your account has been suspended
- Accessing suspended user’s content
- Terms of service violations
try:
await client.create_tweet('Hello!')
except AccountSuspended:
print("Your account has been suspended.")
print("Visit Twitter's help center for more information.")
AccountLocked
Raised when an account is locked and requires verification (often Arkose challenge).
Common Causes:
- Suspicious activity detected
- Security verification required
- Automated behavior detected
- CAPTCHA or challenge required
try:
await client.login(username, password)
except AccountLocked:
print("Account is locked and requires verification.")
print("This often indicates an Arkose challenge is required.")
print("You may need to log in through a web browser.")
Error Handling Patterns
Basic Try-Except
from twikit.errors import TwitterException, TooManyRequests, NotFound
try:
tweet = await client.get_tweet_by_id(tweet_id)
await tweet.favorite()
except NotFound:
print("Tweet not found")
except TooManyRequests as e:
print(f"Rate limited until {e.rate_limit_reset}")
except TwitterException as e:
print(f"Twitter error: {e}")
Retry Logic
import asyncio
from twikit.errors import ServerError, RequestTimeout, TooManyRequests
async def retry_request(func, max_retries=3, *args, **kwargs):
"""Retry a request with exponential backoff."""
for attempt in range(max_retries):
try:
return await func(*args, **kwargs)
except (ServerError, RequestTimeout) as e:
if attempt == max_retries - 1:
raise
wait_time = 2 ** attempt # Exponential backoff
print(f"Request failed. Retrying in {wait_time}s...")
await asyncio.sleep(wait_time)
except TooManyRequests as e:
if e.rate_limit_reset:
wait_time = e.rate_limit_reset - time.time()
print(f"Rate limited. Waiting {wait_time:.0f}s...")
await asyncio.sleep(wait_time)
return await func(*args, **kwargs)
raise
# Usage
tweet = await retry_request(client.get_tweet_by_id, max_retries=3, tweet_id='123')
Graceful Degradation
from twikit.errors import (
UserNotFound, UserUnavailable, AccountSuspended,
TweetNotAvailable, NotFound
)
async def safe_get_user_info(screen_name):
"""Safely get user info with fallback."""
try:
user = await client.get_user_by_screen_name(screen_name)
return {
'name': user.name,
'followers': user.followers_count,
'available': True
}
except UserNotFound:
return {'name': screen_name, 'available': False, 'error': 'not_found'}
except (UserUnavailable, AccountSuspended):
return {'name': screen_name, 'available': False, 'error': 'unavailable'}
except TwitterException as e:
return {'name': screen_name, 'available': False, 'error': str(e)}
user_info = await safe_get_user_info('example_user')
Bulk Operations with Error Handling
from twikit.errors import TwitterException
async def bulk_favorite_tweets(tweet_ids):
"""Favorite multiple tweets with error handling."""
results = {
'success': [],
'failed': [],
'rate_limited': False
}
for tweet_id in tweet_ids:
try:
await client.favorite_tweet(tweet_id)
results['success'].append(tweet_id)
except NotFound:
print(f"Tweet {tweet_id} not found")
results['failed'].append(tweet_id)
except TooManyRequests:
print("Rate limited. Stopping.")
results['rate_limited'] = True
break
except TwitterException as e:
print(f"Failed to favorite {tweet_id}: {e}")
results['failed'].append(tweet_id)
# Small delay between requests
await asyncio.sleep(1)
return results
results = await bulk_favorite_tweets(['123', '456', '789'])
print(f"Favorited: {len(results['success'])}")
print(f"Failed: {len(results['failed'])}")
Logging Errors
import logging
from twikit.errors import TwitterException
logger = logging.getLogger(__name__)
async def logged_request(operation_name, func, *args, **kwargs):
"""Execute a request with comprehensive error logging."""
try:
result = await func(*args, **kwargs)
logger.info(f"{operation_name} succeeded")
return result
except TwitterException as e:
logger.error(
f"{operation_name} failed: {type(e).__name__}: {e}",
extra={'headers': e.headers} if hasattr(e, 'headers') else {}
)
raise
# Usage
await logged_request(
'Get user tweets',
client.get_user_tweets,
user_id,
count=100
)
Best Practices
Always catch specific exceptions before catching the generic TwitterException base class.
When handling TooManyRequests, use the rate_limit_reset attribute to know when you can retry.
Don’t ignore exceptions silently. Always log errors or inform the user about what went wrong.
Be cautious with automatic retries. Excessive retries during rate limiting can lead to longer bans.
Error Code Reference
| Error Code | Exception | Description |
|---|
| 187 | DuplicateTweet | Tweet is a duplicate |
| 324 | InvalidMedia | Invalid or problematic media |
| 400 | BadRequest | Malformed request |
| 401 | Unauthorized | Authentication failed |
| 403 | Forbidden | Access denied |
| 404 | NotFound | Resource not found |
| 408 | RequestTimeout | Request timeout |
| 429 | TooManyRequests | Rate limit exceeded |
| 5xx | ServerError | Server-side error |