DIYgod/RSSHub · error · Error

Twitter API error: ${response.status}

Error message

Twitter API error: ${response.status}

What it means

Generic Error thrown by twitterGot after the rate-limit/auth bookkeeping when response.status >= 400. It is the catch-all for any non-2xx Twitter response that was not already handled as 401/403/429 (those lock or delete the token but still propagate). The status code is embedded so the operator can see what Twitter returned.

Source

Thrown at lib/routes/twitter/api/web-api/utils.ts:236

            //     }
            // }
            // if (auth.password) {
            //     const passwordIndex = config.twitter.password?.indexOf(auth.password);
            //     if (passwordIndex !== undefined && passwordIndex !== -1) {
            //         config.twitter.password?.splice(passwordIndex, 1);
            //     }
            // }
            logger.debug(`twitter debug: delete twitter cookie for token ${auth.token} with status ${response.status}, remaining tokens: ${config.twitter.authToken?.length}`);
            await cache.set(`${lockPrefix}${auth.token}`, '1', 3600);
            // }
        } else {
            logger.debug(`twitter debug: unlock twitter cookie with success for token ${auth.token}`);
            await cache.set(`${lockPrefix}${auth.token}`, '', 1);
        }
    }

    if (response.status >= 400) {
        throw new Error(`Twitter API error: ${response.status}`);
    }

    if (auth?.token) {
        logger.debug(`twitter debug: update twitter cookie for token ${auth.token}`);
        await cache.set(`twitter:cookie:${auth.token}`, JSON.stringify(dispatchers?.jar.serializeSync()), config.cache.contentExpire);
    }

    return responseData;
};

export const paginationTweets = async (endpoint: string, userId: number | undefined, variables: Record<string, any>, path?: string[]) => {
    const params = {
        variables: JSON.stringify({ ...variables, userId }),
        features: JSON.stringify(gqlFeatures[endpoint]),
    };

    const fetchData = async () => {
        if (config.twitter.thirdPartyApi && thirdPartySupportedAPI.includes(endpoint)) {

View on GitHub (pinned to bed535e087)

Solutions

  1. Inspect the embedded status code in the message to classify the failure.
  2. For 5xx, retry after a short backoff (transient Twitter outage).
  3. For 400, update the GraphQL variables/endpoint in the route to match the current Twitter web client.
  4. Check RSSHub logs for the matching 'twitter debug' line showing the full response data and token state.
Defensive patterns

Strategy: retry

Type guard

function isTwitterApiError(e: unknown): e is Error {
  return e instanceof Error && /Twitter API error: \d{3}/.test(e.message);
}
function twitterStatusFromError(e: Error): number | null {
  const m = e.message.match(/(\d{3})$/); return m ? Number(m[1]) : null;
}

Try / catch

try { await twitterGot(url, params); }
catch (e) {
  const status = twitterStatusFromError(e as Error);
  if (status && status >= 500) { await backoff(); retry(); }       // transient
  else if (status === 400) { /* schema changed; update route */ }
  else throw e;
}

Prevention

When it happens

Trigger: Twitter returns 400 (bad GraphQL variables), 404 (endpoint moved), 5xx (Twitter outage), or any other 4xx/5xx not matched by the 401/403/429 branches. Also fires when a 429 slipped through because the rate-limit branch only locks the token but execution continues to this throw.

Common situations: Twitter API deprecation (variables schema changed → 400); Twitter-side incident (5xx); guest-token exhausted on an allowNoAuth path; downstream proxy returned a non-Twitter error status.

Related errors


AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12). Data as JSON: /api/errors/2968b1002b38a902. Report an issue: GitHub.