{"record":{"id":"d674ddc662a7e024","repo":"overleaf/overleaf","slug":"folder-not-found","errorCode":"folder_not_found","errorMessage":"folder_not_found","messagePattern":"folder_not_found","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"services/web/app/src/Features/Project/ProjectEntityUpdateHandler.mjs","lineNumber":401,"sourceCode":"  },\n})\n\nconst upsertDoc = wrapWithLock(\n  async function (projectId, folderId, docName, docLines, source, userId) {\n    if (!SafePath.isCleanFilename(docName)) {\n      throw new Errors.InvalidNameError('invalid element name')\n    }\n    let element, folderPath\n    try {\n      ;({ element, path: folderPath } =\n        await ProjectLocator.promises.findElement({\n          project_id: projectId,\n          element_id: folderId,\n          type: 'folder',\n        }))\n    } catch (error) {\n      if (error instanceof Errors.NotFoundError) {\n        throw new Error('folder_not_found')\n      }\n      throw error\n    }\n\n    if (element == null) {\n      throw new Error(\"Couldn't find folder\")\n    }\n\n    const existingDoc = element.docs.find(({ name }) => name === docName)\n    const existingFile = element.fileRefs.find(({ name }) => name === docName)\n    if (existingFile) {\n      const doc = new Doc({ name: docName })\n      const filePath = `${folderPath.fileSystem}/${existingFile.name}`\n      const { rev } = await DocstoreManager.promises.updateDoc(\n        projectId.toString(),\n        doc._id.toString(),\n        docLines,\n        0,","sourceCodeStart":383,"sourceCodeEnd":419,"githubUrl":"https://github.com/overleaf/overleaf/blob/28ad3b03b71cb4311decdcb55c36b33ec10d72db/services/web/app/src/Features/Project/ProjectEntityUpdateHandler.mjs#L383-L419","documentation":"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.","triggerScenarios":"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.","commonSituations":"Clients caching folder IDs across project copies; concurrent deletion of the target folder; scripts referencing folder IDs from an old project snapshot.","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"],"exampleFix":"// before\nawait handler.promises.upsertDoc(projectId, folderId, name, lines, source, userId)\n// after\ntry {\n  await handler.promises.upsertDoc(projectId, folderId, name, lines, source, userId)\n} catch (err) {\n  if (err.message === 'folder_not_found') {\n    const root = await getRootFolder(projectId)\n    await handler.promises.upsertDoc(projectId, root._id, name, lines, source, userId)\n  } else throw err\n}","handlingStrategy":"try-catch","validationCode":"const folder = await ProjectLocator.promises.findElement({ project_id: projectId, element_id: folderId, type: 'folder' }).catch(() => null)\nif (folder == null) throw new Error('target folder does not exist')","typeGuard":"const folderExists = (result) => result != null && result.element != null","tryCatchPattern":"try {\n  await handler.promises.upsertDoc(projectId, folderId, docName, lines, source, userId)\n} catch (err) {\n  if (err.message === 'folder_not_found') {\n    const [rootFolder] = await ProjectLocator.promises.rootFolder({ project_id: projectId })\n    return handler.promises.upsertDoc(projectId, rootFolder._id, docName, lines, source, userId)\n  }\n  throw err\n}","preventionTips":["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"],"tags":["not-found","folder","concurrency"],"backgroundTag":"folder-not-found","analyzedSha":"28ad3b03b71cb4311decdcb55c36b33ec10d72db","analyzedAt":"2026-09-03T02:10:22.807Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T07:17:11.731Z"}