Skip to main content

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

TwitterException

Base class for all Twitter API related exceptions.
class TwitterException(Exception)

Attributes

headers
dict | None
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

rate_limit_reset
int | None
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

CouldNotTweet

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}")

DuplicateTweet

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}")

TweetNotAvailable

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.")

InvalidMedia

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 CodeExceptionDescription
187DuplicateTweetTweet is a duplicate
324InvalidMediaInvalid or problematic media
400BadRequestMalformed request
401UnauthorizedAuthentication failed
403ForbiddenAccess denied
404NotFoundResource not found
408RequestTimeoutRequest timeout
429TooManyRequestsRate limit exceeded
5xxServerErrorServer-side error

Build docs developers (and LLMs) love