{"record":{"id":"69c1dffa3f92f283","repo":"actualbudget/actual","slug":"invalid-file-id-69c1df","errorCode":"invalid-file-id","errorMessage":"File not found at server","messagePattern":"File not found at server","errorType":"http","errorClass":null,"httpStatus":404,"severity":"error","filePath":"packages/sync-server/src/app-admin.js","lineNumber":208,"sourceCode":"  const { granted } = UserService.checkFilePermission(\n    fileId,\n    res.locals.user_id,\n  ) || {\n    granted: 0,\n  };\n\n  if (granted === 0 && !isAdmin(res.locals.user_id)) {\n    res.status(403).send({\n      status: 'error',\n      reason: 'forbidden',\n      details: 'permission-not-found',\n    });\n    return false;\n  }\n\n  const fileIdInDb = UserService.getFileById(fileId);\n  if (!fileIdInDb) {\n    res.status(404).send({\n      status: 'error',\n      reason: 'invalid-file-id',\n      details: 'File not found at server',\n    });\n    return false;\n  }\n\n  const accesses = UserService.getUserAccess(\n    fileId,\n    res.locals.user_id,\n    isAdmin(res.locals.user_id),\n  );\n\n  res.json(accesses);\n});\n\napp.post('/access', (req, res) => {\n  const userAccess = req.body || {};","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/sync-server/src/app-admin.js#L190-L226","documentation":"The file deletion/validation path calls `UserService.getFileById(fileId)`; if no file row matches, it responds 404 with reason 'invalid-file-id' and details 'File not found at server'. The server only permits operations on files it actually tracks in its files table.","triggerScenarios":"DELETE /user-delete-file (or similar file endpoint) with a fileId that does not exist on the server — already deleted, a local-only file never synced, an id from another server, or a mistyped uuid.","commonSituations":"Deleting a file on the server after it was already removed (double cleanup); pointing a client at a fresh sync-server instance while reusing ids from the old instance; local files created offline that were never uploaded; corrupted client metadata holding stale file ids.","solutions":["Verify the fileId against the server's file list (user-get-files) and use only ids present there.","Treat 404 as already-deleted and remove the file from local metadata instead of retrying.","Confirm the client is connected to the same sync server that hosts the file (check GOAL_SERVER_URL / server URL config).","If the file should exist, re-upload/sync it from the client to register it, then retry the operation."],"exampleFix":"// before\nawait deleteFile({ fileId: localFileId }); // file never synced to this server\n// after\nconst files = await getUserFiles();\nif (files.some(f => f.fileId === localFileId)) {\n  await deleteFile({ fileId: localFileId });\n}","handlingStrategy":"validation","validationCode":"const files = await getUserFiles(); // server-side listing\nif (!files.some(f => f.fileId === fileId)) {\n  throw new Error(`File ${fileId} not present on server; nothing to delete`);\n}","typeGuard":"function isKnownFileId(fileId: string, serverFiles: { fileId: string }[]): boolean {\n  return serverFiles.some(f => f.fileId === fileId);\n}","tryCatchPattern":"try {\n  await deleteFile({ fileId });\n} catch (e) {\n  if (e.status === 404 && e.reason === 'invalid-file-id') {\n    // already deleted or never synced: clean up local metadata only\n    return;\n  }\n  throw e;\n}","preventionTips":["Validate fileIds against the server listing before delete/sync operations.","Treat 404 invalid-file-id as success in cleanup scripts (idempotent deletes).","Confirm the client's sync-server URL matches the server that hosts the file.","Remove stale local file metadata after successful deletion to prevent repeats."],"tags":["http-404","not-found","files","sync-server"],"backgroundTag":"entity-not-found","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}