overleaf/overleaf · error · OError
Project blocked from loading docs
Error message
Project blocked from loading docs
What it means
putDocInMemory throws this OError when the project is currently blocked from loading docs (Redis key indicating the project was blocked, e.g. after too many concurrent load attempts or a project-level lock). Docs are refused to avoid adding docIds to a blocked project's docsInProject set while it is being unloaded or quarantined.
Source
Thrown at services/document-updater/app/js/RedisManager.js:86
logger.debug(
{ projectId, docId, version, docHash, pathname, projectHistoryId },
'putting doc in redis'
)
ranges = RedisManager._serializeRanges(ranges)
// update docsInProject set before writing doc contents
const projectBlockMulti = rclient.multi()
projectBlockMulti.exists(keys.projectBlock({ project_id: projectId }))
projectBlockMulti.sadd(keys.docsInProject({ project_id: projectId }), docId)
const reply = await projectBlockMulti.exec()
const projectBlocked = reply[0] === 1
if (projectBlocked) {
// We don't clean up the spurious docId added in the docsInProject
// set. There is a risk that the docId was successfully added by a
// concurrent process. This set is used when unloading projects. An
// extra docId will not prevent the project from being uploaded, but
// a missing docId means that the doc might stay in Redis forever.
throw new OError('Project blocked from loading docs', { projectId })
}
await RedisManager.setHistoryRangesSupportFlag(docId, historyRangesSupport)
if (!pathname) {
metrics.inc('pathname', 1, {
path: 'RedisManager.setDoc',
status: pathname === '' ? 'zero-length' : 'undefined',
})
}
// Make sure that this MULTI operation only operates on doc
// specific keys, i.e. keys that have the doc id in curly braces.
// The curly braces identify a hash key for Redis and ensures that
// the MULTI's operations are all done on the same node in a
// cluster environment.
const multi = rclient.multi()
multi.mset({View on GitHub (pinned to 28ad3b03b7)
Solutions
- Wait for the block TTL to expire and retry loading the project
- Clear the project block key in Redis if it is stale (rclient DEL the block key) after verifying the project is healthy
- Investigate why the project got blocked (too many docs / memory pressure) and reduce doc count or size
- Check for retry storms from web hammering loadDoc and add backoff
Example fix
try {
await documentUpdaterHandler.promises.flushProjectToMongo(projectId)
} catch (err) {
if (err.message === 'Project blocked from loading docs') {
await timer(30_000) // let the block expire
return retry()
}
throw err
} Defensive patterns
Strategy: retry
Try / catch
try {
await putDocInMemory(...)
} catch (err) {
if (err.message === 'Project blocked from loading docs') return retryAfterBlockExpiry(projectId)
throw err
} Prevention
- Throttle concurrent project loads to avoid triggering the block
- Check the project block key in Redis before bulk loads
- Investigate root causes (project size, doc count) that lead to blocking
- Use backoff, not tight retry loops, or the block will persist
When it happens
Trigger: Calling putDocInMemory while the project block flag exists in Redis (projectBlocked truthy), typically set when the project exceeds concurrency/size limits or during controlled unloading.
Common situations: Projects with very large numbers of docs hitting load limits; burst of concurrent loadDoc/flush requests after a project structure change; stale block flag left after a crash; misconfigured blocking thresholds.
Related errors
- blocking doc insert into redis: doc is too large
- redis getDoc exceeded timeout
- redis getPreviousDocOps exceeded timeout
- Oops, something went wrong
- doc would become too large if appending this text
AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03).
Data as JSON: /api/errors/fb5dff7e6d3b3a60.
Report an issue: GitHub.