{"record":{"id":"28fc064bb179b76c","repo":"actualbudget/actual","slug":"file-not-found-28fc06","errorCode":null,"errorMessage":"File not found","messagePattern":"File not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/sync-server/src/services/user-service.ts","lineNumber":139,"sourceCode":"        oldUserId,\n      ]);\n    });\n  } catch (error) {\n    throw new Error(`Failed to transfer files: ${error.message}`);\n  }\n}\n\nexport function updateFileOwner(ownerId, fileId) {\n  if (!ownerId || !fileId) {\n    throw new Error('Invalid parameters');\n  }\n  try {\n    const result = getAccountDb().mutate(\n      'UPDATE files set owner = ? WHERE id = ?',\n      [ownerId, fileId],\n    );\n    if (result.changes === 0) {\n      throw new Error('File not found');\n    }\n  } catch (error) {\n    throw new Error(`Failed to update file owner: ${error.message}`);\n  }\n}\n\nexport function getUserAccess(fileId, userId, isAdmin) {\n  return getAccountDb().all(\n    `SELECT users.id as userId, user_name as userName, files.owner, display_name as displayName\n     FROM users\n     JOIN user_access ON user_access.user_id = users.id\n     JOIN files ON files.id = user_access.file_id\n     WHERE files.id = ? and (files.owner = ? OR 1 = ?)`,\n    [fileId, userId, isAdmin ? 1 : 0],\n  );\n}\n\nexport function countUserAccess(fileId, userId) {","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/sync-server/src/services/user-service.ts#L121-L157","documentation":"updateFileOwner runs an UPDATE on files and checks result.changes; if the UPDATE matched zero rows it throws 'File not found', meaning no file with the given id exists. This distinguishes a no-op update from a successful ownership change.","triggerScenarios":"Calling updateFileOwner with a fileId that does not exist in the files table — deleted file, id from a different budget/database, typo'd or truncated id, or fileId pointing to a file the requesting server instance never synced.","commonSituations":"Client holds a stale file id after the file was deleted server-side; restoring a database from backup so newer file ids are gone; multi-instance setups where files live in a different account.sqlite; passing the internal cloud file id vs the local budget id interchangeably.","solutions":["Confirm the fileId exists: getFileById(fileId) should return a row before updating","Re-fetch the current file list from the server; if the file was deleted, remove the stale reference on the client","Verify you are querying the same account database the file was created in","Check for id mismatch (cloud file id vs local id) and use the id stored in the files table"],"exampleFix":"// before\nawait updateFileOwner(newOwnerId, fileId); // throws if deleted\n// after\nif (!getFileById(fileId)) {\n  logger.warn(`File ${fileId} no longer exists; skipping owner update`);\n  return;\n}\nawait updateFileOwner(newOwnerId, fileId);","handlingStrategy":"validation","validationCode":"import { getFileById } from './services/user-service';\nif (!getFileById(fileId)) {\n  throw new Error(`File ${fileId} does not exist; refresh file list`);\n}","typeGuard":"function fileExists(fileId) {\n  return typeof fileId === 'string' && fileId.length > 0 && getFileById(fileId) !== null;\n}","tryCatchPattern":"try {\n  updateFileOwner(ownerId, fileId);\n} catch (e) {\n  if (e.message.includes('File not found')) {\n    logger.warn(`Skipping owner update for missing file ${fileId}`);\n    return;\n  }\n  throw e;\n}","preventionTips":["Re-fetch the file list from the server instead of trusting cached ids","Handle deleted files gracefully in admin UIs (skip, not crash)","Distinguish cloud file ids from local budget ids","Verify all instances point at the same account database"],"tags":["sync-server","file-not-found","stale-id","database"],"backgroundTag":"entity-not-found","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}