{"record":{"id":"80b802963465d774","repo":"actualbudget/actual","slug":"failed-to-delete-user-access-error-message","errorCode":null,"errorMessage":"Failed to delete user access: ${error.message}","messagePattern":"Failed to delete user access: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/sync-server/src/services/user-service.ts","lineNumber":105,"sourceCode":"export function deleteUser(userId) {\n  return getAccountDb().transaction(() => {\n    const { changes } = getAccountDb().mutate(\n      'DELETE FROM users WHERE id = ? and owner = 0',\n      [userId],\n    );\n    if (changes > 0) {\n      getAccountDb().mutate('DELETE FROM sessions WHERE user_id = ?', [userId]);\n    }\n    return changes;\n  });\n}\nexport function deleteUserAccess(userId) {\n  try {\n    return getAccountDb().mutate('DELETE FROM user_access WHERE user_id = ?', [\n      userId,\n    ]).changes;\n  } catch (error) {\n    throw new Error(`Failed to delete user access: ${error.message}`);\n  }\n}\n\nexport function transferAllFilesFromUser(ownerId, oldUserId) {\n  if (!ownerId || !oldUserId) {\n    throw new Error('Invalid user IDs');\n  }\n  try {\n    getAccountDb().transaction(() => {\n      const ownerExists = getUserById(ownerId);\n      if (!ownerExists) {\n        throw new Error('New owner not found');\n      }\n      getAccountDb().mutate('UPDATE files set owner = ? WHERE owner = ?', [\n        ownerId,\n        oldUserId,\n      ]);\n    });","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/sync-server/src/services/user-service.ts#L87-L123","documentation":"deleteUserAccess(userId) wraps any error from the DELETE on the user_access table and rethrows as 'Failed to delete user access: <original message>'. It preserves the underlying SQLite error (constraint, locked DB, etc.) while adding context about the operation.","triggerScenarios":"The DELETE FROM user_access WHERE user_id = ? fails — database file locked by another process, disk I/O error, corrupted schema, or missing user_access table (old/unmigrated account DB).","commonSituations":"Admin deleting a user while another sync-server process holds a write lock; running the server against a read-only filesystem; account DB from an older version lacking the user_access table.","solutions":["Read the wrapped error.message for the root SQLite cause and fix that first.","Ensure no other process holds a write lock on the account SQLite file; stop duplicate server instances.","Run migrations so the user_access table exists in the account DB.","Check filesystem permissions / disk space for the SQLite database location."],"exampleFix":"// before\ndeleteUserAccess('user-123');   // Error: Failed to delete user access: SQLITE_BUSY: database is locked\n// after\n// stop the second server instance / retry after lock clears, then\ndeleteUserAccess('user-123');","handlingStrategy":"try-catch","validationCode":"// ensure the DB is writable and the table exists first\nconst row = getAccountDb().first('SELECT user_id FROM user_access WHERE user_id = ?', [userId]);\nif (row === undefined) console.warn(`No user_access rows for ${userId}; nothing to delete`);","typeGuard":"function isUserAccessDeletionError(err: unknown): err is Error {\n  return err instanceof Error && err.message.startsWith('Failed to delete user access:');\n}","tryCatchPattern":"try {\n  deleteUserAccess(userId);\n} catch (err) {\n  if (isUserAccessDeletionError(err)) {\n    logger.error('user_access delete failed; underlying cause: %s', err.message.replace('Failed to delete user access: ', ''));\n    // surface 500 and advise fixing DB locks/permissions, then retry\n    return;\n  }\n  throw err;\n}","preventionTips":["Run only one sync-server process against the account SQLite DB.","Confirm filesystem write permissions and free disk space for the DB.","Keep migrations current so user_access exists.","Back up the account DB before destructive admin operations."],"tags":["database","sqlite","sync-server","user-management"],"backgroundTag":"database-write-failed","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}