overleaf/overleaf · error · DocRevValueError
failed to unarchive doc
Error message
failed to unarchive doc
What it means
restoreArchivedDoc calls db.docs.updateOne with a pipeline built from the stored update and expects exactly one document to match the query. If matchedCount !== 1 (0 matches), the archived doc is not present under the given query (docId/rev), so the unarchive silently failed. The library throws DocRevValueError to surface this as a failed restore rather than returning a stale result.
Source
Thrown at services/docstore/app/js/MongoManager.js:233
_id: new ObjectId(docId),
project_id: new ObjectId(projectId),
rev: archivedDoc.rev,
}
const update = {
$set: {
lines: archivedDoc.lines,
ranges: archivedDoc.ranges || {},
},
$unset: {
inS3: true,
},
}
const pipeline = convertUpdateToPipeline(update)
const payloadSize = BSON.calculateObjectSize(pipeline)
Metrics.count('mongo_docs_write', payloadSize, 1, { method: 'restore' })
const result = await db.docs.updateOne(query, pipeline)
if (result.matchedCount !== 1) {
throw new Errors.DocRevValueError('failed to unarchive doc', {
docId,
rev: archivedDoc.rev,
})
}
}
async function getDocRev(docId) {
const doc = await db.docs.findOne(
{ _id: new ObjectId(docId.toString()) },
{ projection: { rev: 1 } }
)
return doc && doc.rev
}
/**
* Helper method to support optimistic locking.
*
* Check that the rev of an existing doc is unchanged. If the rev hasView on GitHub (pinned to 28ad3b03b7)
Solutions
- Verify the doc still exists in the docs collection with the expected archived state/rev before calling restoreArchivedDoc.
- Handle the race by retrying: re-fetch the archived doc and call restore again if another process changed it.
- Check the docId is correct and the doc was actually archived (not deleted) before restoring.
- Catch Errors.DocRevValueError in the caller and return a 404/409 to the HTTP client instead of a 500.
Example fix
// before
await docstoreManager.unArchiveDoc(projectId, docId)
// after
try {
await docstoreManager.unArchiveDoc(projectId, docId)
} catch (err) {
if (err instanceof Errors.DocRevValueError) {
return res.status(404).json({ error: 'archived doc not found or already restored' })
}
throw err
} Defensive patterns
Strategy: try-catch
Validate before calling
const archived = await db.docs.findOne({ _id: docId })
if (!archived || archived.rev !== expectedRev) {
throw new Error(`archived doc ${docId} not present with rev ${expectedRev}`)
} Type guard
function isRestoreable(doc) {
return doc != null && typeof doc.rev === 'number' && !Number.isNaN(doc.rev)
} Try / catch
try {
await MongoManager.restoreArchivedDoc(docId, rev)
} catch (err) {
if (err instanceof Errors.DocRevValueError) {
// doc already restored or gone — treat as 404/409, do not retry blindly
return { status: 404 }
}
throw err
} Prevention
- Check the archived doc's existence and rev immediately before restoring.
- Make unarchive operations idempotent so races between processes are harmless.
- Return 404/409 to clients rather than letting DocRevValueError bubble up as a 500.
- Log docId and rev on failure to speed up race diagnosis.
When it happens
Trigger: Calling MongoManager.restoreArchivedDoc (e.g. via the docstore unarchive HTTP endpoint) when the doc no longer exists in the archived collection under the query, or the archived doc's rev changed between read and update, so updateOne matches 0 documents.
Common situations: Race where another process unarchives or deletes the archived doc between the fetch and the updateOne; stale docId passed by a caller; retry of an already-completed unarchive; replica-set failover causing a lost update window.
Related errors
- rejecting stale update
- doc rev is NaN
- doc rev has changed
- chunk start version is not unique
- ParallelLoginError
AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03).
Data as JSON: /api/errors/f68530b83ff18575.
Report an issue: GitHub.