WEIR

Tweepy 403 Forbidden in 2026: Every Error and Its Fix

Tweepy 403 Forbidden in 2026: what each Tweepy error means now, how to confirm the cause, and a 12-line Python script that searches X with no developer account.


Published · Updated · 7 min read

Cover image: Every Tweepy error, decoded

A Tweepy 403 Forbidden means X accepted your credentials but refused the call, because your app lacks access to that endpoint. Check your app's access in the Developer Console first.

This page is for developers whose Tweepy script worked on an older X (Twitter) API tier and now fails. You get one section per Tweepy error, with its cause, a way to confirm it, and the fix. If you only need to read public posts, a 12-line script near the end skips the developer account.

python -c "import tweepy; print(tweepy.__version__)"
403valid login, no permission
401bad or missing credentials
402no class in Tweepy
429wait for the reset
  1. Print the errorRead error.response.status_code and error.api_messages.
  2. Match the code403 access, 401 token, 402 credits, 429 limit.
  3. Apply the fixEach section below gives the check and the fix.

Tweepy 403 Forbidden: the app is not allowed

In Tweepy, tweepy.errors.Forbidden is raised for any 403 status code. Tweepy's source shows it is a subclass of HTTPException.

X's response-codes page, checked on 12 November 2026, describes a 403 as "Valid auth but no permission for this resource or action." It lists the error type client-forbidden with the text "App not enrolled or lacks required access."

So the token works, and the app does not. Three causes fit that wording:

  • The endpoint needs different access than your app has. X's pay-per-usage plan is the model on its pricing page today.
  • The app has no credits or plan. The pricing page says you buy credits in the Developer Console.
  • A write call with a read-only app. Tweepy's own FAQ says to "make sure your app has the write permission."

To confirm, print what X said. Tweepy stores it on the exception:

try:
    client.search_recent_tweets(query="python")
except tweepy.Forbidden as error:
    print(error.response.status_code, error.api_codes, error.api_messages)

Tweepy fills api_messages from the errors list in the response body, or from the detail field if there is none. Read that text before you change anything.

The fix is in the Developer Console at console.x.com. Open the app, check its access and its credits, then try again.

Tweepy errors Unauthorized 401: the token is not accepted

tweepy.errors.Unauthorized is raised for a 401. X's page calls a 401 "Invalid or missing authentication credentials."

The usual causes are a wrong or regenerated bearer token, a token with a stray space or quote from an .env file, or a token from a different app. A 401 is about who you are. A 403 is about what you may do.

To confirm, print the exact string Tweepy sends and compare it with the console:

import os
token = os.environ.get("X_BEARER_TOKEN", "")
print(len(token), repr(token[:6]), repr(token[-4:]))

An empty length means the variable never loaded. Quotes or \n in the repr mean a bad paste. Regenerate the token in the console, store it again, and rerun.

Tweepy 402 payment required: out of credits

Tweepy has no PaymentRequired class. Its request code raises named errors for 400, 401, 403, 404, 429 and 5xx. Any other failing status becomes the base tweepy.HTTPException.

So a 402 shows up as a plain HTTPException, with the status in error.response.status_code. X's response-codes page does not list a 402, as of 12 November 2026.

The pricing page does explain the likely cause. It says requests are blocked until you add credits to cover a negative balance. Our X API 402 Payment Required guide has the full fix.

except tweepy.HTTPException as error:
    if error.response.status_code == 402:
        raise SystemExit("Out of X API credits. Top up, then rerun.")
    raise

Do not retry a 402. Nothing changes until someone pays.

Tweepy 429 too many requests: limit or cap

tweepy.errors.TooManyRequests is raised for a 429. X says exceeding limits "results in a 429 error until the window resets."

The response headers tell you when. x-rate-limit-reset is a Unix timestamp. X lists 450 recent-search requests per 15 minutes for an app token and 300 for a user token.

Tweepy can wait for you. With wait_on_rate_limit=True it sleeps until the reset time plus one second, then retries. Without it, TooManyRequests carries the reset time in its reset_time attribute.

client = tweepy.Client(bearer_token=token, wait_on_rate_limit=True)

Waiting does not fix a usage cap.

X's pricing page caps pay-per-usage plans at 3 million post reads per monthly billing cycle. Its error list names a separate usage-capped type, "Usage cap exceeded."

Does Tweepy still work, and is Tweepy free?

Yes to both, with a catch. Tweepy 4.17.0, released on 2 July 2026 per PyPI, is current, and PyPI lists the MIT license. The library is free.

The calls are not. As of 12 November 2026, X's pricing page lists pay-per-usage: $0.005 per post read and $0.010 per user read. Plans are capped at 3 million post reads per month, and the page describes no free tier. Price your job with the X API cost calculator.

The same search without a developer account

If your script only reads public posts, you can skip the app, the console and Tweepy. We ran this search on 12 November 2026 with the Weir MCP tool search_x, asking for 5 recent original posts from @XDevelopers.

X returned 2, and the call charged 3 credits: 1 for the call and 1 per post. The first post, trimmed:

{
  "id": "2120289321693630734",
  "text": "Your agent can no longer send an 𝕏 Chat to your ex by mistake",
  "createdAt": "2026-11-10T22:55:42.000Z",
  "author": { "username": "XDevelopers" },
  "likeCount": 412,
  "viewCount": 22444
}

The second item was a repost, so we left it out. This script mirrors that MCP call. It uses only urllib.request and json, and calls POST /v1/x/search from Weir's OpenAPI file:

import json, os, urllib.request

body = {"fromUsers": ["XDevelopers"], "onlyOriginal": True, "limit": 5}
headers = {
    "Authorization": "Bearer " + os.environ["WEIR_API_KEY"],
    "Content-Type": "application/json",
}
url = "https://api.weirapp.io/v1/x/search"
req = urllib.request.Request(url, json.dumps(body).encode(), headers)
with urllib.request.urlopen(req, timeout=60) as r:
    print("credits:", r.headers["x-credits-charged"])
    for post in json.load(r)["data"]:
        print(post["createdAt"][:10], post["likeCount"], post["text"][:50])

We ran it too, and it printed credits: 3 and the same two dates. A 402 here is Weir's quota_exceeded, and it is never retryable.

Get a key at weirapp.io/signup. To move a whole Tweepy script over, read how to migrate from the X API v2 to Weir. To keep Tweepy, start with the Tweepy tutorial. For the other X error codes, see X API error codes.

When not to use Weir

We run Weir, so weigh this knowing that. Weir is read-only and not licensed by X, so access can change.

  • You post, like, follow or send DMs. Only X's official API and Tweepy can write.
  • You work on your own account. Your own timeline, bookmarks and settings need your own login.
  • You need a contract with X. Weir is a third party.
  • Your 403 is on a write call. Fix the app's permissions instead.

FAQ

Why do I get tweepy errors forbidden 403 forbidden?

X accepted your credentials but your app is not allowed to make that call. Print error.api_messages to read X's reason. Then check the app's access, credits and read or write permission in the Developer Console.

What does tweepy errors unauthorized 401 unauthorized mean?

X did not accept the token. It is wrong, empty, expired or from another app. Regenerate the bearer token, store it without quotes, and print its length to be sure it loaded.

How do I handle a tweepy 402 payment required error?

Catch tweepy.HTTPException and check for status 402, because Tweepy has no class for it. It points to an empty credit balance on X's pay-per-usage plan. Add credits. Retrying does not help.

Why do I get tweepy 429 too many requests?

You passed a rate limit or a usage cap. Read x-rate-limit-reset, or set wait_on_rate_limit=True so Tweepy sleeps until the reset. If your monthly cap is spent, waiting will not help.

Is there a tweepy alternative for reading tweets?

For reading public posts, yes: a REST API such as Weir, called with plain Python. It cannot post or act on your account. For writes, stay on Tweepy and X's API.

Sources