{"record":{"id":"8beebe060cc9caba","repo":"DIYgod/RSSHub","slug":"cooling-down-before-new-visitor-cookies-from-url","errorCode":null,"errorMessage":"Cooling down before new visitor Cookies from ${url} may be fetched","messagePattern":"Cooling down before new visitor Cookies from (.+?) may be fetched","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"lib/routes/weibo/utils.ts","lineNumber":73,"sourceCode":"                    throw new Error('Cookies expired. Please update WEIBO_COOKIES');\n                }\n                return config.weibo.cookies;\n            }\n\n            const cacheKey = 'weibo:visitor-cookies';\n            if (renew) {\n                cache.set(cacheKey, '', 1);\n            }\n            return await cache.tryGet(cacheKey, async () => {\n                if (visitorCookiesPromise) {\n                    return await visitorCookiesPromise;\n                }\n                if (coolingDown) {\n                    if (renew?.message) {\n                        logger.warn(coolingDownMessage);\n                        throw renew;\n                    }\n                    throw new Error(coolingDownMessage);\n                }\n                coolingDown = true;\n                setTimeout(() => {\n                    coolingDown = false;\n                }, config.cache.routeExpire * 1000);\n\n                if (renew) {\n                    logger.warn(`Renewing visitor Cookies from ${url}`);\n                } else {\n                    logger.info(`Fetching visitor Cookies from ${url}`);\n                }\n                visitorCookiesPromise = (async () => {\n                    let times = 0;\n                    const { page, destroy } = await getPlaywrightPage(url, {\n                        onBeforeLoad: async (page) => {\n                            const expectResourceTypes = new Set(['document', 'script', 'xhr', 'fetch']);\n                            await page.setExtraHTTPHeaders({ 'User-Agent': weiboUtils.apiHeaders['User-Agent'] });\n                            await page.route('**/*', (route) => {","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/weibo/utils.ts#L55-L91","documentation":"A self-imposed cooldown guard inside getCookies(). After a visitor-cookie fetch attempt, coolingDown stays true for config.cache.routeExpire seconds; any further request that is NOT carrying a RenewWeiboCookiesError (i.e. renew is false or a plain boolean true with no .message) is rejected to avoid hammering m.weibo.cn with headless browser launches.","triggerScenarios":"A second request arrives while coolingDown is true and renew is falsy or a boolean (renew?.message is undefined), hitting the throw at utils.ts:73. Triggered by bursty traffic or concurrent route calls before the routeExpire cooldown elapses.","commonSituations":"Many readers polling weibo routes simultaneously right after startup or right after a prior fetch failure; aggressive RSS refresh intervals stacked on top of each other.","solutions":["Wait config.cache.routeExpire seconds (the cooldown window) and retry — the guard clears automatically.","Set WEIBO_COOKIES to bypass the visitor-cookie fetch path entirely.","Stagger/space out polling of weibo routes so concurrent calls do not collide during cooldown."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Track the cooldown window before issuing concurrent weibo requests\nconst routeExpireMs = (Number(process.env.CACHE_ROUTE_EXPIRE ?? 300)) * 1000;\nconst lastFetch = sharedState.lastWeiboVisitorFetch ?? 0;\nif (Date.now() - lastFetch < routeExpireMs) {\n    // skip or queue instead of triggering the cooldown throw\n}","typeGuard":"function isWeiboCooldownError(e: unknown): boolean {\n    return e instanceof Error && /Cooling down before new visitor Cookies/i.test(e.message);\n}","tryCatchPattern":"for (const delay of [0, 5_000, 15_000]) {\n    try {\n        return await weiboUtils.getCookies(false);\n    } catch (e) {\n        if (!isWeiboCooldownError(e) || delay === 15_000) throw e;\n        await new Promise((r) => setTimeout(r, delay));\n    }\n}","preventionTips":["Serialize weibo route requests through a single queue to avoid concurrent cooldown collisions.","Prefer WEIBO_COOKIES for production loads to avoid the visitor-fetch cooldown entirely.","Respect config.cache.routeExpire as the minimum spacing between weibo fetches."],"tags":["weibo","cookies","rate-limit","cooldown"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}