DIYgod/RSSHub · warning · RequestInProgressError
This path is currently fetching, please come back later!
Error message
This path is currently fetching, please come back later!
What it means
Thrown as RequestInProgressError by the cache middleware when a cache miss occurs but another request already holds the fetch 'claim' for that key. The current request polls the controlKey up to 10 times (6s apart in prod, 3s/1 retry in test); if the holder never releases within ~60s, this error surfaces. RSSHub maps RequestInProgressError to HTTP 503-ish 'try again later'.
Source
Thrown at lib/middleware/cache.ts:49
if (!value) {
isRequesting = !(await cacheModule.globalCache.claim(controlKey, config.cache.requestTimeout));
}
if (isRequesting) {
let retryTimes = process.env.NODE_ENV === 'test' ? 1 : 10;
let bypass = false;
while (retryTimes > 0) {
// eslint-disable-next-line no-await-in-loop
await new Promise((resolve) => setTimeout(resolve, process.env.NODE_ENV === 'test' ? 3000 : 6000));
// eslint-disable-next-line no-await-in-loop
if ((await cacheModule.globalCache.get(controlKey)) !== '1') {
bypass = true;
break;
}
retryTimes--;
}
if (!bypass) {
throw new RequestInProgressError('This path is currently fetching, please come back later!');
}
value = await cacheModule.globalCache.get(key);
}
if (value) {
ctx.status(200);
ctx.header('RSSHub-Cache-Status', 'HIT');
ctx.set('data', JSON.parse(value));
await next();
return;
}
if (isRequesting) {
// waited out a stale claim without finding a cache entry, take over the fetch
await cacheModule.globalCache.set(controlKey, '1', config.cache.requestTimeout);
}
// let routers control cacheView on GitHub (pinned to bed535e087)
Solutions
- Retry the request after a short backoff (this is transient).
- Raise config.cache.requestTimeout so the claim outlives slow upstream fetches.
- Reduce per-request latency: enable upstream caching, lower route limit, or optimize the route.
- Scale the instance so the first fetcher is not CPU-starved behind other heavy routes.
Example fix
// config: give the fetcher longer before peers give up CACHE_REQUEST_TIMEOUT=120 // client: exponential backoff retry on 503
Defensive patterns
Strategy: retry
Validate before calling
// Nothing to validate pre-call; this is a server-side transient state. // Client strategy: detect 503 + this message and back off. const shouldRetry = (status: number, body: string) => status === 503 && /currently fetching/.test(body);
Try / catch
for (const delay of [5, 10, 20]) {
try { return await fetch(url); }
catch (e) {
if (!/currently fetching/.test(String(e?.message ?? ''))) throw e;
await sleep(delay * 1000);
}
} Prevention
- Set CACHE_REQUEST_TIMEOUT longer than your slowest route fetch.
- Stagger feed-reader polls to avoid thundering herds on cache expiry.
- Monitor upstream latency so you notice when fetches start overrunning the retry window.
When it happens
Trigger: Two or more concurrent requests for the same path+format+limit while the cache is cold; the winning fetch takes longer than (retryCount * interval) because the upstream source is slow or the route does heavy work; config.cache.requestTimeout expires and the claim is held stale.
Common situations: Feed reader hammers a freshly-deployed route on cache expiry; upstream site is rate-limited/slow so the first fetch overruns the retry window; Redis claim TTL (requestTimeout) shorter than the slowest realistic fetch.
Related errors
- Category not found
- Tag not found
- WASM function not available
- Failed to fetch announcements, error code: ' + result?.code
- Failed to fetch announcements
AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12).
Data as JSON: /api/errors/ec8c549359f0ca2f.
Report an issue: GitHub.