{"record":{"id":"2968b1002b38a902","repo":"DIYgod/RSSHub","slug":"twitter-api-error-response-status","errorCode":null,"errorMessage":"Twitter API error: ${response.status}","messagePattern":"Twitter API error: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/routes/twitter/api/web-api/utils.ts","lineNumber":236,"sourceCode":"            //     }\n            // }\n            // if (auth.password) {\n            //     const passwordIndex = config.twitter.password?.indexOf(auth.password);\n            //     if (passwordIndex !== undefined && passwordIndex !== -1) {\n            //         config.twitter.password?.splice(passwordIndex, 1);\n            //     }\n            // }\n            logger.debug(`twitter debug: delete twitter cookie for token ${auth.token} with status ${response.status}, remaining tokens: ${config.twitter.authToken?.length}`);\n            await cache.set(`${lockPrefix}${auth.token}`, '1', 3600);\n            // }\n        } else {\n            logger.debug(`twitter debug: unlock twitter cookie with success for token ${auth.token}`);\n            await cache.set(`${lockPrefix}${auth.token}`, '', 1);\n        }\n    }\n\n    if (response.status >= 400) {\n        throw new Error(`Twitter API error: ${response.status}`);\n    }\n\n    if (auth?.token) {\n        logger.debug(`twitter debug: update twitter cookie for token ${auth.token}`);\n        await cache.set(`twitter:cookie:${auth.token}`, JSON.stringify(dispatchers?.jar.serializeSync()), config.cache.contentExpire);\n    }\n\n    return responseData;\n};\n\nexport const paginationTweets = async (endpoint: string, userId: number | undefined, variables: Record<string, any>, path?: string[]) => {\n    const params = {\n        variables: JSON.stringify({ ...variables, userId }),\n        features: JSON.stringify(gqlFeatures[endpoint]),\n    };\n\n    const fetchData = async () => {\n        if (config.twitter.thirdPartyApi && thirdPartySupportedAPI.includes(endpoint)) {","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/twitter/api/web-api/utils.ts#L218-L254","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the embedded status code in the message to classify the failure.","For 5xx, retry after a short backoff (transient Twitter outage).","For 400, update the GraphQL variables/endpoint in the route to match the current Twitter web client.","Check RSSHub logs for the matching 'twitter debug' line showing the full response data and token state."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"function isTwitterApiError(e: unknown): e is Error {\n  return e instanceof Error && /Twitter API error: \\d{3}/.test(e.message);\n}\nfunction twitterStatusFromError(e: Error): number | null {\n  const m = e.message.match(/(\\d{3})$/); return m ? Number(m[1]) : null;\n}","tryCatchPattern":"try { await twitterGot(url, params); }\ncatch (e) {\n  const status = twitterStatusFromError(e as Error);\n  if (status && status >= 500) { await backoff(); retry(); }       // transient\n  else if (status === 400) { /* schema changed; update route */ }\n  else throw e;\n}","preventionTips":["Treat 5xx as transient with exponential backoff.","Log the embedded status code so dashboards can separate Twitter outages from local issues.","Watch for 400 storms — they signal an upstream GraphQL schema change requiring a route update."],"tags":["twitter","http-status","api-error","network"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}