X API ErrorsTwitter API Error CodesHTTP Status CodesRate LimitsTroubleshooting

X (Twitter) API Error Codes: Reference and Retry Rules

X API status codes, error type URIs and the numeric codes behind them, with the cause and the fix for each, plus the partial-error case that returns HTTP 200.

GetXAPI·
Abstract blue and orange landscape of monolithic blocks reflected in still water

Every X API integration eventually returns something other than 200. This reference covers the responses you are most likely to hit and what each one means: the HTTP status codes, the error type URIs in the response envelope, the numeric codes X passes back from its older error vocabulary, and the partial-error case that hides failures inside a successful response.

Codes and messages here are taken from X's own Response Codes and Errors documentation and from the GetXAPI error reference, checked on 20 August 2026.

TL;DR: The status code tells you the class of failure, the type URI tells you the specific condition, and the detail string tells you which resource caused it. Read all three before writing a retry. A 403 from a protected account will keep failing until something changes about the access, the target or your credentials, so do not retry it automatically; a 502 on a read usually clears on the next attempt. And a 200 is not proof of success, because partial errors ship failures inside the success envelope.

What Is an X API Error Code?

An X API error code is the machine-readable identifier X returns when a request cannot be completed as asked. Modern v2 responses carry three of them at once: an HTTP status code for the class of failure, a type URI naming the specific condition, and, when the failure originates deep in X's stack, a numeric code from the older error vocabulary.

HTTP Status Codes

The status code is the coarsest signal. It tells you which family the failure belongs to, and therefore whether a retry has any chance of working.

Success codes

Code Meaning Description
200 OK Request successful. May still contain a partial errors array, see below
201 Created Resource created, returned by POST requests
204 No Content Success with no response body, returned by DELETE requests

Client error codes

These mean the request was wrong. Retrying an identical request produces an identical failure.

Code Meaning Common causes
400 Bad Request Invalid JSON, malformed query, missing required parameters
401 Unauthorized Invalid or missing authentication credentials
403 Forbidden Valid auth but no permission for this resource or action
404 Not Found Resource does not exist or has been deleted
409 Conflict Stream has no rules, filtered stream only
429 Too Many Requests Rate limit or usage cap exceeded

Server error codes

These mean X failed, not you. All four are worth retrying with backoff.

Code Meaning What to do
500 Internal Server Error Wait and retry, check the X status page
502 Bad Gateway Wait and retry
503 Service Unavailable X is overloaded, wait and retry
504 Gateway Timeout Wait and retry

The Error Response Envelope

X returns structured error bodies rather than bare strings. The shape is consistent enough to branch on directly.

{
  "title": "Invalid Request",
  "detail": "The 'query' parameter is required.",
  "type": "https://api.x.com/2/problems/invalid-request"
}
Field Description
type URI identifying the error type. This is the field to branch on
title Short error description
detail Specific explanation, usually naming the offending parameter or resource

The type, title and detail trio matches the shape defined by RFC 9457 Problem Details for HTTP APIs, which replaced RFC 7807 in 2023. X does not document the envelope as RFC 9457 and does not guarantee an application/problem+json content type, so treat the resemblance as convenient rather than contractual: an existing problem-details handler is a reasonable starting point, but validate the fields you depend on rather than assuming conformance.

Branch on type, not on title or detail. The URI is a stable identifier; the human-readable strings are not contractual and can be reworded without notice.

X Error Type URIs

Eleven type URIs cover the conditions you will meet in practice. The paths below are relative to https://api.x.com/2/problems/.

Type Description Retry?
about:blank Generic error, fall back to the HTTP status code Depends on status
invalid-request Malformed request or invalid parameters No, fix the request
resource-not-found Post, user or other resource does not exist No
not-authorized-for-resource No access to private or protected content Not unchanged, only after access changes
client-forbidden App not enrolled or lacks required access No, fix app access
usage-capped Usage cap exceeded Not until the cap resets
rate-limit-exceeded Rate limit exceeded Yes, after the reset time
streaming-connection Stream connection problem Yes, reconnect
rule-cap Too many filtered stream rules No, delete rules first
invalid-rules Rule syntax error No, fix the rule
duplicate-rules Rule already exists No, already present

Note that usage-capped and rate-limit-exceeded both surface as 429 but are entirely different conditions. A backoff loop clears the second and does nothing at all for the first.

Start building with GetXAPI

$0.05 per 1,000 tweets. $0.10 free credits. No credit card required.

Numeric Error Codes You Will Actually Hit

X also returns numeric codes from its older error vocabulary, particularly on write operations and account-level failures. These arrive as a separate field alongside the HTTP status, surfaced by GetXAPI as twitter_error_code, so the same number can mean something entirely different from the HTTP status that carries it. These are the ones that appear in real logs.

Code Meaning What to do
32 Could not authenticate you The token is invalid or expired, re-mint it
63 The target account is suspended Nothing, the account is gone
64 Your account is suspended Use a different account
131 Temporary X internal error Retry
139 Already liked Already done, safe to ignore
144 No post found with that ID Deleted, or the ID is wrong
187 Duplicate post Change the text or wait about 15 minutes
226 Request looked automated Retry
326 Account temporarily locked Unlock the account, then retry
327 Already reposted Already done, safe to ignore
344 Posting temporarily limited at the network level Retry shortly, or route through a clean dedicated IP
349 Cannot message this user The recipient does not accept your DMs
399 Wrong password or could not log in Check credentials, or retry after a temporary login limit
433 Reply restricted or Premium required The post is reply-gated, or the action needs X Premium
465 Cannot repost an outdated post The post is too old to repost
476 Not allowed to send message requests The account cannot send DM requests
502 Daily DM (message request) limit reached, arrives inside an HTTP 429, not to be confused with HTTP 502 Wait 24 hours, or use an account with higher limits

Three of these are worth calling out because they are routinely mishandled. Codes 139 and 327 are not failures at all: the action you asked for is already true, and treating them as errors makes idempotent retries look broken. Code 344 is a network-level throttle rather than an account-level one, so switching accounts does not help and switching egress IP does.

Partial Errors: A 200 That Contains Failures

This is the single most commonly missed case in X API integrations, and it is worth handling before anything else on this page.

When you request several resources at once and some are unavailable, X returns 200 with both data and errors populated:

{
  "data": [
    {"id": "123", "text": "Hello"}
  ],
  "errors": [
    {
      "resource_id": "456",
      "resource_type": "tweet",
      "title": "Not Found Error",
      "detail": "Could not find tweet with id: [456].",
      "type": "https://api.x.com/2/problems/resource-not-found"
    }
  ]
}

Client code written as if response.ok: process(response.data) treats this as a clean success and silently drops the missing records. In a batch lookup of a thousand posts where forty were deleted, you get nine hundred and sixty results and no indication that anything went wrong. The bug surfaces weeks later as unexplained gaps in the dataset.

A gift box labelled HTTP 200 with a green tick, holding good tweet cards while two failed cards fall unnoticed through a hole in the bottom, captioned check the errors array

Always check for an errors key even on a 200. The resource_type values you will see there are the same object names used throughout X's data dictionary.

Rate Limit Headers

When you hit 429, the response headers tell you exactly when to try again. Reading them is strictly better than a fixed sleep, because a fixed sleep is either too short, which compounds the problem, or too long, which wastes throughput.

X documents rate limit headers on the same Response Codes and Errors page, and the per-endpoint windows on its rate limits reference. Read the reset value, wait until it, then retry once. Do not retry in a tight loop: X documents waiting for the reset and backing off, and a tight loop simply spends quota on requests that cannot succeed yet.

The status code itself dates to RFC 6585, which introduced 429 precisely so servers could distinguish "you are asking too often" from "you are not allowed", which is why treating 429 as an auth problem sends debugging in the wrong direction.

A Diagnostic Order That Converges

Most debugging time is lost checking things in the wrong order. This sequence eliminates the largest class of causes first.

  1. Read the response body, not just the status. The detail field usually names the exact parameter or resource at fault. Two 403s with different detail strings are different bugs.
  2. Check for a partial error. If the status is 200, confirm there is no errors array before assuming success.
  3. Branch on the type URI. This distinguishes usage-capped from rate-limit-exceeded, which the status code alone cannot.
  4. Classify by what would have to change. Server errors and code 131 clear on their own, so a retry is appropriate. A protected or suspended target will not clear on its own: only a change in the target's state, your access level, or your credentials makes that request succeed, so do not retry it unchanged.
  5. Only then check your credentials. Auth is the most common first guess and one of the least common actual causes once you are past initial setup.

Two doors: an open one labelled retry works, waits on its own with codes 500 and 131, and a closed one labelled needs access, target or credentials to change with codes 403 and 32, captioned do not retry unchanged

The cheapest Twitter API. Try it free.

$0.05 per 1,000 tweets. $0.10 free credits. No credit card required.

Test Your Error Handling in Three Languages

The pattern is the same everywhere: check the status, then check for partial errors, then branch on the type URI.

import requests

r = requests.get(url, headers=headers, timeout=30)

# 204 has no body, and a 5xx can arrive as HTML from a proxy, so never
# call .json() unconditionally.
body = {}
if r.status_code != 204 and "application/json" in r.headers.get("content-type", ""):
    try:
        body = r.json()
    except ValueError:
        body = {}

if r.status_code == 204:
    pass                                  # success, nothing to parse
elif r.ok:
    for e in body.get("errors", []):      # partial failure inside a 200
        print("partial failure:", e.get("type"), e.get("detail"))
    process(body.get("data", []))
elif r.status_code == 429:
    print("throttled, honour the reset header before retrying")
else:
    print(r.status_code, body.get("type"), body.get("detail") or r.text[:200])
const r = await fetch(url, { headers });

// 204 has no body and a proxy 5xx may be HTML, so guard the parse.
let body = {};
if (r.status !== 204 && r.headers.get("content-type")?.includes("application/json")) {
  body = await r.json().catch(() => ({}));
}

if (r.status === 204) {
  // success, nothing to parse
} else if (r.ok) {
  for (const e of body.errors ?? []) {
    console.warn("partial failure:", e.type, e.detail);
  }
  process(body.data ?? []);
} else if (r.status === 429) {
  console.warn("throttled, honour the reset header before retrying");
} else {
  console.error(r.status, body.type, body.detail);
}
curl -sS -w '\nHTTP %{http_code}\n' \
  -H "Authorization: Bearer $TOKEN" \
  "https://api.x.com/2/tweets?ids=123,456"

The cURL form is worth keeping in your notes: -w '\nHTTP %{http_code}\n' prints the status alongside the body, which is what you need when a 200 is hiding an errors array.

Errors by Operation

Some failures only appear on particular operations. These are the ones worth knowing in advance.

Operation HTTP twitter_error_code Condition Retry?
Read posts or search 403 n/a Target is protected, suspended, or inactive Not unchanged
Read posts or search 502 n/a Transient upstream hiccup Yes, usually clears immediately
Create post 403 187 Duplicate text No, change the text
Create post 429 344 Network-level posting throttle Yes, after a short wait
Like or repost 403 139, 327 Action already performed No, treat as success
Follow or unfollow 403 326 Account temporarily locked Only after unlocking
Send DM 403 349, 476 Recipient does not accept DMs from you Not unchanged
Send DM 429 502 Daily message request limit reached After 24 hours
Login 401 399 Bad credentials or temporary login limit Once, after a wait

The two 502s are unrelated. HTTP 502 is a transient upstream failure and is worth retrying. twitter_error_code: 502, which arrives inside an HTTP 429, is the daily message-request limit and is not. Branching on the number alone without checking which field it came from will retry a quota limit as though it were a gateway blip.

Two envelopes both stamped 502: HTTP 502 points to a healthy server and means transient, retry, while error code 502 points to a closed shutter and means daily DM limit, wait

A protected target returning 403 and an upstream blip returning HTTP 502 both look like "no posts came back", but they call for opposite handling. The first will not succeed until something changes; the second usually clears on retry. Conflating them is why some crawlers hammer unavailable accounts indefinitely.

What Changes on a Managed API

Going through a managed provider does not remove X's error vocabulary, it wraps it. On GetXAPI, failures originating at X are passed through with X's own code in a twitter_error_code field, so the numeric table above still applies, and the provider adds its own codes for conditions X never sees:

  • 401 covers key problems: missing, malformed, or revoked
  • 402 means the account is out of credits, and nothing is charged automatically
  • 403 covers account-level restrictions and target-level or action-level denials
  • 429 covers capacity throttling as well as X-side account limits, and carries a retry_after value to honour

There is no endpoint-specific quota to plan around, though general service throttling still applies, so sustained concurrency can return 429 and long-running jobs should be wrapped in a retry with backoff. Transient upstream failures on reads and network-level throttles such as code 344 are not billed. The full behaviour is documented in the GetXAPI error reference.

Frequently Asked Questions

What does X API error 32 mean?

Code 32 is "Could not authenticate you". The credential presented with the request is invalid, expired, or was minted for a different account. It is not a rate limit and not a permission problem, so retrying the same request with the same credential fails identically. Re-mint the token and retry once.

Why does the X API return 403 when my token is valid?

403 means authentication succeeded but the action is not permitted. The four common causes are a protected or suspended target account, an app lacking the required access level, an action that needs X Premium, and a reply-gated post. Read the detail field: a 403 caused by a protected target will not resolve by retrying the same request, only by the target's state or your access changing.

What is a partial error in the X API?

A partial error is an HTTP 200 that contains both a data array and an errors array. It happens when you request several resources and only some are available, for example looking up five posts where one was deleted. Code that only checks the status code treats this as a clean success and silently drops the missing records.

How should I handle a 429 from the X API?

Read the rate limit headers rather than guessing. X returns the reset time, and a well-behaved client waits until then instead of retrying immediately. A 429 can also mean a usage cap rather than a per-window rate limit, and those are different conditions with different fixes, so check the type URI before assuming a backoff will clear it.

Do failed X API calls still cost money?

It depends on the failure and the provider. On GetXAPI, transient upstream failures such as a 502 on a read, and network-level throttles such as code 344, are not billed. Check your provider's documented billing behaviour for errors rather than assuming, because a retry loop against a billed error class gets expensive quickly.

Frequently Asked Questions

Code 32 is "Could not authenticate you". The credential presented with the request is invalid, expired, or was minted for a different account. It is not a rate limit and not a permission problem, so retrying the same request with the same credential will fail identically. Re-mint the token and retry once.

A partial error is an HTTP 200 response that contains both a data array and an errors array. It happens when you request several resources and only some are available, for example looking up five posts where one was deleted. Code that only checks the status code will treat this as a clean success and silently drop the missing records.

It depends on the failure and the provider. On GetXAPI, transient upstream failures such as a 502 on a read, and network-level throttles such as code 344, are not billed. Check your provider's documented billing behaviour for errors rather than assuming, because a retry loop against a billed error class gets expensive quickly.

403 means authentication succeeded but the action is not permitted. The four common causes are a protected or suspended target account, an app that lacks the required access level, an action that needs X Premium, and a reply-gated post. Read the detail field: a 403 caused by a protected target will not resolve by retrying the same request, only by the target's state or your access changing.

Read the rate limit headers rather than guessing. X returns the reset time, and a well-behaved client waits until then instead of retrying immediately. A 429 can also mean a usage cap rather than a per-window rate limit, and those are different conditions with different fixes, so check the error type URI before assuming a backoff will clear it.

Check out similar blogs

More guides on the Twitter/X API, scraping, and pricing.

Diagnosing Twitter X API 403 Forbidden and 401 Unauthorized errors, with the cause and fix for each
Twitter APIX API

Twitter API 403 Forbidden and 401 Unauthorized: Every Cause and Fix

Why the X API returns 403 Forbidden or 401 Unauthorized, how to tell the two apart, and a fix for each cause. Covers tier gating, app permissions, OAuth, and X error codes.

GetXAPI·
The best Twitter and X API alternatives in 2026 compared across managed APIs, scraping marketplaces, and open-source libraries
Twitter APIX API

The Best Twitter (X) API Alternatives in 2026, Compared

The best Twitter / X API alternatives in 2026, ranked and compared: managed pay-per-call APIs, web-data marketplaces, and open-source libraries, with real per-1,000-tweet costs.

GetXAPI·
How to like a tweet via API in 2026: a single call to the favorite endpoint, no X developer account required
Twitter APIX API

How to Like a Tweet via API in 2026 (No Dev Account)

Like (favorite) tweets programmatically via API in 2026 without an X developer account. The auth_token model, working curl, Python, and Node code, and per-call cost.

GetXAPI·
Best Twitter and X tools of 2026 by category: data APIs, schedulers, analytics, and monitoring
Twitter ToolsX Tools

The Best Twitter/X Tools in 2026, by Category

The best Twitter/X tools of 2026 for creators, marketers, and developers, spanning scheduling, analytics, scraping, monitoring, AI writers, and data APIs.

GetXAPI·
Building a Twitter bot in 2026 with no-code and Python paths, runnable code, and current X API cost facts
Twitter BotX Bot

How to Build a Twitter Bot in 2026: The Complete Guide

Build a Twitter bot in 2026 with no-code or Python. Working Tweepy and requests code, auth explained, and the cheap API path at $0.05 per 1,000 reads.

GetXAPI·
How to post tweets via API with authentication in 2026 using a registered X auth_token, no developer account required
Twitter APIX API

Post Tweets via API With Authentication in 2026 (No Developer Account)

Post tweets, threads, and media through an API without an X developer account. The auth_token model, working Python and Node code, rate-limit safety, and per-call costs.

GetXAPI·
Seven Twitter API use cases that work without an X developer account in 2026
twitter-apix-api

7 Twitter API Use Cases With No X Developer Account (2026)

The current public X pricing page lists pay-per-use and Enterprise access. Here are 7 Twitter data use cases you can ship without an X developer account.

GetXAPI·
Per-1,000-tweet cost comparison across 8 Twitter API providers in 2026, including hidden billing costs
twitter-apiapi-comparison

Cheapest Twitter API 2026: 8 Providers Ranked by Real Per-1,000-Tweet Cost

We pulled real pricing pages, ran the math at three volume tiers, and ranked every major Twitter API provider by what you actually pay per 1,000 tweets, including hidden costs most comparison posts skip.

GetXAPI·