{"record":{"id":"676a6d0270cad8b8","repo":"DIYgod/RSSHub","slug":"twitter-cookie-for-token-auth-token-replace","errorCode":null,"errorMessage":"Twitter cookie for token ${auth?.token?.replace(/(\\w{8})(\\w+)/, (_, v1, v2) => v1 + '*'.repeat(v2.length))} is not valid","messagePattern":"Twitter cookie for token (.+?)\\)\\(\\\\w\\+\\)/, \\(_, v1, v2\\) => v1 \\+ '\\*'\\.repeat\\(v2\\.length\\)\\)\\} is not valid","errorType":"exception","errorClass":"ConfigNotFoundError","httpStatus":null,"severity":"error","filePath":"lib/routes/twitter/api/web-api/utils.ts","lineNumber":125,"sourceCode":"        logger.debug(`twitter debug: got twitter cookie for token ${auth?.token}`);\n        if (typeof cookie === 'string') {\n            cookie = JSON.parse(cookie);\n        }\n        const jar = CookieJar.deserializeSync(cookie as any);\n        const agent = proxy.proxyUri\n            ? new ProxyAgent({\n                  uri: proxy.proxyUri,\n              }).compose(HttpCookieAgentCookie({ jar }))\n            : new CookieAgent({ cookies: { jar } });\n        if (proxy.proxyUri) {\n            logger.debug(`twitter debug: Proxying request: ${requestUrl}`);\n        }\n        dispatchers = {\n            jar,\n            agent,\n        };\n    } else if (auth) {\n        throw new ConfigNotFoundError(`Twitter cookie for token ${auth?.token?.replace(/(\\w{8})(\\w+)/, (_, v1, v2) => v1 + '*'.repeat(v2.length))} is not valid`);\n    }\n    const jsonCookie = dispatchers\n        ? Object.fromEntries(\n              dispatchers.jar\n                  .getCookieStringSync(url)\n                  .split(';')\n                  .map((c) => Cookie.parse(c)?.toJSON())\n                  .map((c) => [c?.key, c?.value])\n          )\n        : {};\n\n    // Use undici.fetch directly instead of ofetch.raw to preserve the CookieAgent\n    // dispatcher. Two layers drop it in the normal path:\n    //   1. ofetch does not forward `dispatcher` to its internal fetch() call\n    //   2. wrappedFetch (request-rewriter) does `new Request(input, init)` which\n    //      discards non-standard options like `dispatcher`\n    // Additionally, setting `cookie` header manually doesn't work either because\n    // the Fetch spec treats `cookie` as a forbidden header name, so","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/twitter/api/web-api/utils.ts#L107-L143","documentation":"ConfigNotFoundError thrown when an auth token was found (getAuth returned one) but token2Cookie(auth.token) could not produce a usable cookie jar. RSSHub caches the deserialized cookie per token; if the cached cookie is missing/corrupt or the token-to-cookie exchange failed, it cannot build the CookieAgent dispatcher and rejects the request rather than sending an unauthenticated call.","triggerScenarios":"auth.token resolves but the cached 'twitter:cookie:<token>' entry was evicted, expired, or stored a malformed JSON; token2Cookie returned falsy; the login() fallback path that used to repair cookies is commented out, so there is no automatic recovery. The masked token id is logged to help identify which configured token is bad.","commonSituations":"Cache backend was flushed between requests; the token's cookie was never successfully minted (first use after token rotation); Redis/memory cache evicted the entry under memory pressure; token revoked by Twitter so the exchange returns nothing.","solutions":["Identify the masked token in the message and remove/replace that exact TWITTER_AUTH_TOKEN entry.","Clear the stale cache keys 'twitter:cookie:<token>' and the lock key so a fresh exchange is attempted.","Obtain a fresh auth_token cookie from a logged-in x.com session and update the env.","Restart RSSHub after updating config."],"exampleFix":"// before: stale/revoked token in env\n// TWITTER_AUTH_TOKEN=oldtoken\n// after\n// TWITTER_AUTH_TOKEN=newtoken  (re-extracted from x.com cookie 'auth_token')","handlingStrategy":"retry","validationCode":"// Before the call, confirm a cached cookie exists for at least one token.\nasync function anyValidCookie(tokens: string[], cache): Promise<boolean> {\n  for (const t of tokens) { if (await cache.get(`twitter:cookie:${t}`)) return true; }\n  return false;\n}","typeGuard":"function isValidCookieJar(serialized: unknown): boolean {\n  try { return !!serialized && typeof (serialized as any).cookies !== 'undefined'; }\n  catch { return false; }\n}","tryCatchPattern":"try { await twitterGot(url, params); }\ncatch (e) {\n  if (/cookie .* is not valid/.test(String(e))) {\n    // evict the bad token's cache and retry with the next token\n    await cache.del(`twitter:cookie:${masked}`);\n    return retryWithNextToken();\n  }\n  throw e;\n}","preventionTips":["Keep more than one auth token so a single bad cookie does not take the route down.","Monitor for repeated 'cookie is not valid' for the same token and rotate it proactively.","Ensure the cache backend has enough memory/TTL that cookie entries are not prematurely evicted."],"tags":["twitter","config-not-found","cookie","auth","cache"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}