{"record":{"id":"14ef526c1416ef1d","repo":"overleaf/overleaf","slug":"unrecognised-file-not-in-snapshot","errorCode":null,"errorMessage":"unrecognised file: not in snapshot","messagePattern":"unrecognised file: not in snapshot","errorType":"exception","errorClass":"OError","httpStatus":null,"severity":"error","filePath":"services/project-history/app/js/SyncManager.js","lineNumber":895,"sourceCode":"      Metrics.inc('project_history_resync_operation', 1, {\n        status: 'update binary file contents',\n      })\n    }\n  }\n\n  /**\n   * Expand a resyncDocContentUpdate\n   *\n   * @param {ResyncDocContentUpdate} update\n   */\n  async expandResyncDocContentUpdate(update) {\n    const pathname = UpdateTranslator._convertPathname(update.path)\n    const snapshotFile = this.files[pathname]\n    const expectedFile = update.resyncDocContent\n    const expectedContent = expectedFile.content\n\n    if (!snapshotFile) {\n      throw new OError('unrecognised file: not in snapshot')\n    }\n\n    // Compare hashes to see if the persisted file matches the expected content.\n    // The hash of the persisted files is stored in the snapshot.\n    // Note getHash() returns the hash only when the persisted file has\n    // no changes in the snapshot, the hash is null if there are changes\n    // that apply to it.\n    let hashesMatch = false\n    const persistedHash = snapshotFile.getHash()\n    if (persistedHash != null) {\n      const expectedHash = HashManager._getBlobHashFromString(expectedContent)\n      if (persistedHash === expectedHash) {\n        logger.debug(\n          { projectId: this.projectId, persistedHash, expectedHash },\n          'skipping diff because hashes match and persisted file has no ops'\n        )\n        hashesMatch = true\n      }","sourceCodeStart":877,"sourceCodeEnd":913,"githubUrl":"https://github.com/overleaf/overleaf/blob/28ad3b03b71cb4311decdcb55c36b33ec10d72db/services/project-history/app/js/SyncManager.js#L877-L913","documentation":"expandResyncDocContentUpdate resolves the doc's pathname via UpdateTranslator._convertPathname and looks it up in this.files (the snapshot's file map). If no entry exists, the resync expects content for a file the snapshot does not know about, so it throws OError('unrecognised file: not in snapshot') — the snapshot and the resync request are inconsistent.","triggerScenarios":"A resyncDocContent update references update.path that, after pathname conversion, is absent from the snapshot's files map — e.g. the file was deleted, renamed, or the snapshot was loaded for the wrong historyId.","commonSituations":"File renamed/deleted between resync initiation and processing; resync run against a stale snapshot (older historyId); case-sensitivity or pathname-conversion differences between web and history services.","solutions":["Reload the snapshot for the current historyId so it includes the file","Skip doc-content resync for deleted files, or re-run a full project-structure resync to realign snapshot and expectations","Verify path conversion matches how the snapshot keys files (UpdateTranslator._convertPathname vs raw path)","Ensure resync start and update processing use the same project version/history snapshot"],"exampleFix":"// before\nconst snapshotFile = this.files[pathname]\nif (!snapshotFile) throw new OError('unrecognised file: not in snapshot')\n// after: tolerate files removed since resync started\nconst snapshotFile = this.files[pathname]\nif (!snapshotFile) {\n  logger.warn({ projectId: this.projectId, pathname }, 'file gone from snapshot; skipping resync')\n  return []\n}","handlingStrategy":"validation","validationCode":"const pathname = UpdateTranslator._convertPathname(update.path)\nif (!snapshot.files[pathname]) { logger.warn({ path: update.path }, 'file absent from snapshot; skipping doc resync'); return }","typeGuard":"function fileInSnapshot(files, pathname) { return files != null && Object.prototype.hasOwnProperty.call(files, pathname) }","tryCatchPattern":"try { await expandResync(update) } catch (err) { if (err instanceof OError && err.message === 'unrecognised file: not in snapshot') { await reloadSnapshotForCurrentHistoryId(); return expandResync(update) } throw err }","preventionTips":["Keep resync initiation and processing on the same historyId/snapshot","Re-run full structure resync after renames/deletes","Log pathname conversions to catch path-normalization drift"],"tags":["snapshot","resync","path-resolution","consistency"],"backgroundTag":"file-not-in-snapshot","analyzedSha":"28ad3b03b71cb4311decdcb55c36b33ec10d72db","analyzedAt":"2026-09-03T02:10:22.807Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T07:17:11.731Z"}