Skip to main content
Twikit provides a comprehensive set of exception classes for handling errors that occur when interacting with Twitter’s API. Understanding these errors helps you build robust applications.

Exception hierarchy

All Twikit exceptions inherit from the base TwitterException class:
from twikit.errors import (
    TwitterException,      # Base exception
    BadRequest,           # 400 errors
    Unauthorized,         # 401 errors
    Forbidden,            # 403 errors
    NotFound,             # 404 errors
    RequestTimeout,       # 408 errors
    TooManyRequests,      # 429 errors
    ServerError,          # 5xx errors
    AccountSuspended,     # Account suspended
    AccountLocked,        # Account locked
    UserNotFound,         # User doesn't exist
    UserUnavailable,      # User unavailable
    CouldNotTweet,        # Tweet failed
    DuplicateTweet,       # Duplicate tweet
    TweetNotAvailable,    # Tweet not available
    InvalidMedia,         # Invalid media ID
)

HTTP status code errors

These exceptions map to standard HTTP status codes:

BadRequest (400)

Raised when the request is malformed or invalid:
try:
    # Invalid parameters
    await client.create_tweet('')  # Empty tweet
except BadRequest as e:
    print(f'Bad request: {e}')
    print(f'Status code: 400')
Common causes:
  • Invalid parameters
  • Missing required fields
  • Malformed data

Unauthorized (401)

Raised when authentication fails or credentials are invalid:
from twikit.errors import Unauthorized

try:
    await client.login(
        auth_info_1='wrong_username',
        password='wrong_password'
    )
except Unauthorized as e:
    print(f'Authentication failed: {e}')
    print('Check your credentials')
Common causes:
  • Invalid username or password
  • Expired session cookies
  • Missing authentication headers

Forbidden (403)

Raised when you don’t have permission to access a resource:
from twikit.errors import Forbidden

try:
    # Try to access a private account's tweets
    tweets = await client.get_user_tweets(private_user_id, 'Tweets')
except Forbidden as e:
    print(f'Access forbidden: {e}')
    print('You may not have permission to view this content')
Common causes:
  • Accessing private/protected content
  • Blocked by the user
  • Insufficient permissions

NotFound (404)

Raised when a resource doesn’t exist:
from twikit.errors import NotFound

try:
    tweet = await client.get_tweet_by_id('invalid_id')
except NotFound as e:
    print(f'Resource not found: {e}')
    print('The tweet may have been deleted')
Common causes:
  • Deleted tweets or accounts
  • Invalid IDs
  • Typos in usernames

RequestTimeout (408)

Raised when a request takes too long:
from twikit.errors import RequestTimeout

try:
    tweets = await client.search_tweet('query', 'Latest')
except RequestTimeout as e:
    print(f'Request timed out: {e}')
    print('The server took too long to respond')
Common causes:
  • Network issues
  • Twitter server overload
  • Complex queries

TooManyRequests (429)

Raised when you exceed rate limits:
from twikit.errors import TooManyRequests
import time
import asyncio

try:
    for i in range(100):  # Too many requests!
        await client.search_tweet(f'query_{i}', 'Latest')
except TooManyRequests as e:
    print(f'Rate limit exceeded: {e}')
    
    # Get the reset time
    if e.rate_limit_reset:
        wait_seconds = e.rate_limit_reset - int(time.time())
        print(f'Rate limit resets in {wait_seconds} seconds')
        print(f'Reset at timestamp: {e.rate_limit_reset}')
        
        # Wait for the rate limit to reset
        await asyncio.sleep(wait_seconds)
    else:
        # Wait 15 minutes if no reset time provided
        await asyncio.sleep(900)
Common causes:
  • Making too many requests in a 15-minute window
  • Not implementing rate limit handling
  • Running multiple scripts simultaneously
The TooManyRequests exception has a special rate_limit_reset attribute containing a Unix timestamp of when the limit resets. Use this to calculate the exact wait time.

ServerError (5xx)

Raised when Twitter’s servers encounter an error:
from twikit.errors import ServerError

try:
    tweets = await client.get_timeline()
except ServerError as e:
    print(f'Server error: {e}')
    print('Twitter\'s servers are experiencing issues')
    # Retry after a delay
    await asyncio.sleep(60)
Common causes:
  • Twitter outages
  • Server maintenance
  • Internal server errors

Account-specific errors

AccountSuspended

Raised when an account is suspended by Twitter:
from twikit.errors import AccountSuspended

try:
    await client.login(
        auth_info_1='username',
        password='password'
    )
except AccountSuspended as e:
    print(f'Account suspended: {e}')
    print('Your account has been suspended by Twitter')
    print('Visit https://help.twitter.com/en/managing-your-account/suspended-twitter-accounts')
What to do:
  • Review Twitter’s rules and policies
  • Appeal the suspension through Twitter’s help center
  • Do not attempt to circumvent the suspension

AccountLocked

Raised when an account is locked (often due to CAPTCHA challenges):
from twikit.errors import AccountLocked
from twikit._captcha import Capsolver

try:
    await client.create_tweet('Hello, world!')
except AccountLocked as e:
    print(f'Account locked: {e}')
    print('Visit https://twitter.com/account/access to unlock')
    
    # Or use automatic unlock with Capsolver
    if client.captcha_solver:
        print('Attempting automatic unlock...')
        await client.unlock()
What to do:
  • Visit the account access page to verify your identity
  • Use a Capsolver instance for automatic unlocking
  • Reduce automation activity temporarily

User and content errors

UserNotFound

Raised when a user doesn’t exist:
from twikit.errors import UserNotFound

try:
    user = await client.get_user_by_screen_name('nonexistent_user_12345')
except UserNotFound as e:
    print(f'User not found: {e}')
    print('The username may be incorrect or the account was deleted')

UserUnavailable

Raised when a user is temporarily unavailable:
from twikit.errors import UserUnavailable

try:
    user = await client.get_user_by_id('12345')
except UserUnavailable as e:
    print(f'User unavailable: {e}')
    print('The user account is temporarily unavailable')

TweetNotAvailable

Raised when a tweet is not available:
from twikit.errors import TweetNotAvailable

try:
    tweet = await client.get_tweet_by_id('12345')
except TweetNotAvailable as e:
    print(f'Tweet not available: {e}')
Common causes:
  • Tweet was deleted
  • Tweet from suspended account
  • Age-restricted content
  • Geographic restrictions

Tweet creation errors

CouldNotTweet

Base exception for tweet creation failures:
from twikit.errors import CouldNotTweet

try:
    tweet = await client.create_tweet('My tweet content')
except CouldNotTweet as e:
    print(f'Could not send tweet: {e}')

DuplicateTweet

Raised when trying to post a duplicate tweet:
from twikit.errors import DuplicateTweet

try:
    await client.create_tweet('Hello, world!')
    await client.create_tweet('Hello, world!')  # Duplicate!
except DuplicateTweet as e:
    print(f'Duplicate tweet: {e}')
    print('This tweet is identical to a recent tweet')
What to do:
  • Modify the tweet text slightly
  • Wait before posting the same content again
  • Add a timestamp or unique identifier

InvalidMedia

Raised when there’s a problem with uploaded media:
from twikit.errors import InvalidMedia

try:
    media_id = await client.upload_media('image.jpg', wait_for_completion=True)
    await client.create_tweet('Check this out!', media_ids=[media_id])
except InvalidMedia as e:
    print(f'Invalid media: {e}')
    print('The media file may be corrupted or in an unsupported format')
Common causes:
  • Corrupted media files
  • Unsupported file formats
  • File size exceeds limits
  • Media processing failed

Common error handling patterns

Basic try/except

from twikit.errors import TwitterException

try:
    tweets = await client.search_tweet('python', 'Latest')
    for tweet in tweets:
        print(tweet.text)
except TwitterException as e:
    print(f'An error occurred: {e}')
    print(f'Error type: {type(e).__name__}')

Multiple exception types

from twikit.errors import NotFound, Forbidden, TooManyRequests

try:
    user = await client.get_user_by_screen_name('someuser')
    tweets = await user.get_tweets('Tweets')
except NotFound:
    print('User not found')
except Forbidden:
    print('Cannot access this user (private or blocked)')
except TooManyRequests as e:
    print(f'Rate limited. Reset at: {e.rate_limit_reset}')

Retry with exponential backoff

import asyncio
from twikit.errors import TooManyRequests, ServerError

async def fetch_with_retry(fetch_func, max_retries=3):
    """Retry a function with exponential backoff."""
    for attempt in range(max_retries):
        try:
            return await fetch_func()
        except TooManyRequests as e:
            if attempt == max_retries - 1:
                raise
            
            wait_time = 2 ** attempt * 60
            if e.rate_limit_reset:
                wait_time = min(wait_time, e.rate_limit_reset - int(time.time()))
            
            print(f'Rate limited. Retrying in {wait_time}s...')
            await asyncio.sleep(wait_time)
        
        except ServerError as e:
            if attempt == max_retries - 1:
                raise
            
            wait_time = 2 ** attempt * 10
            print(f'Server error. Retrying in {wait_time}s...')
            await asyncio.sleep(wait_time)

# Usage
tweets = await fetch_with_retry(
    lambda: client.search_tweet('query', 'Latest')
)

Graceful degradation

from twikit.errors import NotFound, Forbidden, TwitterException

async def get_user_safely(screen_name):
    """Get user with fallback handling."""
    try:
        user = await client.get_user_by_screen_name(screen_name)
        return user
    except NotFound:
        print(f'User @{screen_name} not found')
        return None
    except Forbidden:
        print(f'User @{screen_name} is private or has blocked you')
        return None
    except TwitterException as e:
        print(f'Error fetching @{screen_name}: {e}')
        return None

# Use it
user = await get_user_safely('someuser')
if user:
    print(f'Found user: {user.name}')
else:
    print('Could not retrieve user')

Logging errors

import logging
from twikit.errors import TwitterException

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

async def safe_operation():
    try:
        await client.create_tweet('Hello, world!')
        logger.info('Tweet posted successfully')
    except TwitterException as e:
        logger.error(f'Failed to post tweet: {e}', exc_info=True)
        # Continue with other operations

Accessing error details

All exceptions include response headers:
try:
    tweets = await client.search_tweet('query', 'Latest')
except TwitterException as e:
    print(f'Error message: {e}')
    
    # Access response headers if available
    if e.headers:
        print(f'Rate limit remaining: {e.headers.get("x-rate-limit-remaining")}')
        print(f'Rate limit reset: {e.headers.get("x-rate-limit-reset")}')
        print(f'All headers: {e.headers}')

Best practices

1. Always catch specific exceptions first

# Good: Specific to general
try:
    await client.create_tweet('Hello')
except DuplicateTweet:
    print('Duplicate tweet')
except CouldNotTweet:
    print('General tweet error')
except TwitterException:
    print('General Twitter error')

# Bad: General exception catches everything
try:
    await client.create_tweet('Hello')
except TwitterException:  # This catches ALL Twitter errors
    print('Some error')

2. Handle rate limits proactively

import time
from twikit.errors import TooManyRequests

async def rate_limited_search(queries):
    """Search with automatic rate limit handling."""
    results = []
    
    for query in queries:
        try:
            tweets = await client.search_tweet(query, 'Latest')
            results.append(tweets)
        except TooManyRequests as e:
            if e.rate_limit_reset:
                wait_time = e.rate_limit_reset - int(time.time())
                print(f'Waiting {wait_time}s for rate limit reset')
                await asyncio.sleep(wait_time)
                # Retry
                tweets = await client.search_tweet(query, 'Latest')
                results.append(tweets)
    
    return results

3. Log errors for debugging

import traceback

try:
    await client.create_tweet('Hello')
except TwitterException as e:
    print(f'Error: {e}')
    print(f'Type: {type(e).__name__}')
    print('Traceback:')
    traceback.print_exc()

4. Use context managers for cleanup

class TwitterSession:
    def __init__(self, client):
        self.client = client
    
    async def __aenter__(self):
        await self.client.login(
            auth_info_1='username',
            password='password'
        )
        return self.client
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if exc_type is not None:
            print(f'Error occurred: {exc_val}')
        await self.client.logout()

# Usage
async with TwitterSession(client) as session:
    await session.create_tweet('Hello, world!')

Rate limits

Understand rate limits and TooManyRequests errors

Client

Learn about client initialization and authentication

Build docs developers (and LLMs) love