overleaf/overleaf · error
folder_not_found
folder_not_found
Error message
folder_not_found
What it means
upsertDoc resolves the target folder via ProjectLocator.findElement({ type: 'folder', element_id: folderId }). If that lookup raises Errors.NotFoundError, it is rethrown as a plain Error with message 'folder_not_found', signalling the destination folder does not exist in the project.
Source
Thrown at services/web/app/src/Features/Project/ProjectEntityUpdateHandler.mjs:401
},
})
const upsertDoc = wrapWithLock(
async function (projectId, folderId, docName, docLines, source, userId) {
if (!SafePath.isCleanFilename(docName)) {
throw new Errors.InvalidNameError('invalid element name')
}
let element, folderPath
try {
;({ element, path: folderPath } =
await ProjectLocator.promises.findElement({
project_id: projectId,
element_id: folderId,
type: 'folder',
}))
} catch (error) {
if (error instanceof Errors.NotFoundError) {
throw new Error('folder_not_found')
}
throw error
}
if (element == null) {
throw new Error("Couldn't find folder")
}
const existingDoc = element.docs.find(({ name }) => name === docName)
const existingFile = element.fileRefs.find(({ name }) => name === docName)
if (existingFile) {
const doc = new Doc({ name: docName })
const filePath = `${folderPath.fileSystem}/${existingFile.name}`
const { rev } = await DocstoreManager.promises.updateDoc(
projectId.toString(),
doc._id.toString(),
docLines,
0,View on GitHub (pinned to 28ad3b03b7)
Solutions
- Re-fetch the folder (or project tree) to confirm folderId exists before upserting
- Fall back to the project root folder when the target folder is missing
- Catch the 'folder_not_found' error and recreate the folder via mkdirp before retrying
- Ensure folderId belongs to the same projectId
Example fix
// before
await handler.promises.upsertDoc(projectId, folderId, name, lines, source, userId)
// after
try {
await handler.promises.upsertDoc(projectId, folderId, name, lines, source, userId)
} catch (err) {
if (err.message === 'folder_not_found') {
const root = await getRootFolder(projectId)
await handler.promises.upsertDoc(projectId, root._id, name, lines, source, userId)
} else throw err
} Defensive patterns
Strategy: try-catch
Validate before calling
const folder = await ProjectLocator.promises.findElement({ project_id: projectId, element_id: folderId, type: 'folder' }).catch(() => null)
if (folder == null) throw new Error('target folder does not exist') Type guard
const folderExists = (result) => result != null && result.element != null
Try / catch
try {
await handler.promises.upsertDoc(projectId, folderId, docName, lines, source, userId)
} catch (err) {
if (err.message === 'folder_not_found') {
const [rootFolder] = await ProjectLocator.promises.rootFolder({ project_id: projectId })
return handler.promises.upsertDoc(projectId, rootFolder._id, docName, lines, source, userId)
}
throw err
} Prevention
- Confirm folder existence (or use root folder) when folderId comes from client state
- Handle concurrent deletion races by re-fetching the tree on failure
- Validate folderId belongs to the same project
When it happens
Trigger: Calling upsertDoc with a folderId that was deleted, belongs to another project, or is a stale/invalid ObjectId; passing null folderId where the lookup treats it as missing.
Common situations: Clients caching folder IDs across project copies; concurrent deletion of the target folder; scripts referencing folder IDs from an old project snapshot.
Related errors
- batchedUpdate is already running
- file does not exist
- The operation's base length must be equal to the string's le
- The operation didn't operate on the whole string.
- compile in progress
AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03).
Data as JSON: /api/errors/d674ddc662a7e024.
Report an issue: GitHub.