6.0.0 - Deleting a user via the GUI fails with IntegrityError on MariaDB
- Dominant language
- Python
- Stars
- 74.8k
- Forks
- 18.3k
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 685
Description
### Bug description
# Bug: Deleting a user via the GUI fails with IntegrityError on MariaDB
## Summary
When attempting to delete a user via the Superset Security UI (`Settings → List Users → Delete`), the operation fails silently in the UI with "There was an issue deleting record" and raises an `IntegrityError` in the backend. The user is not deleted. The root cause is that `flask_appbuilder`'s `delete_user()` performs a bare `DELETE FROM ab_user` without cleaning up dependent rows first, and MariaDB foreign keys have no `ON DELETE` rule to handle this automatically.
## Environment
| Component | Version |
|---|---|
| Apache Superset | 6.0.0 |
| flask_appbuilder | ≥ 4.x |
| SQLAlchemy | 2.x |
| Python | 3.11 |
| Database | MariaDB 10.x / 11.x |
> **Note:** PostgreSQL may be unaffected depending on how its FK constraints are created.
## Steps to Reproduce
1. Configure Superset with a MariaDB `SQLALCHEMY_DATABASE_URI`
2. Create at least one non-admin user and have them perform any action (login, view a dashboard, run a query)
3. Navigate to `Settings → Security → List Users`
4. Click the delete icon on any user
5. Observe the error toast: "There was an issue deleting record"
## Error
**UI:** Toast notification: `There was an issue deleting record`
**Backend log:**
```
ERROR:superset.views.base:IntegrityError: (pymysql.err.IntegrityError)
(1451, 'Cannot delete or update a parent row: a foreign key constraint fails
(`superset`.`logs`, CONSTRAINT `logs_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `ab_user` (`id`))')
```
## Root Cause
`flask_appbuilder`'s `SecurityManager.delete_user()` executes a direct `DELETE FROM ab_user WHERE id = ?` without prior cleanup of dependent rows in tables that reference `ab_user.id`.
Superset's Alembic migrations create these foreign keys **without** any `ON DELETE` rule (defaulting to `RESTRICT` in MariaDB). Affected tables include:
| Table | Column | Expected behavior |
|---|---|---|
| `logs` | `user_id` | `SET NULL` (audit log, keep row) |
| `saved_query` | `user_id` | `SET NULL` (keep query, remove owner) |
| `query` | `user_id` | `SET NULL` |
| `favstar` | `user_id` | `CASCADE` (delete user's favorites) |
| `dashboard_user` | `user_id` | `CASCADE` |
| `slice_user` | `user_id` | `CASCADE` |
| `report_schedule_user` | `user_id` | `CASCADE` |
| `sqlatable_user` | `user_id` | `CASCADE` |
| `tab_state` | `user_id` | `CASCADE` |
| `ab_user_role` | `user_id` | `CASCADE` |
| `ab_user_group` | `user_id` | `CASCADE` |
## Fix
Add proper `ON DELETE` rules to all `user_id` foreign keys. For audit/log tables use `SET NULL` to preserve records; for ownership/membership tables use `CASCADE`:
```sql
-- Example for logs table
ALTER TABLE `logs` DROP FOREIGN KEY `logs_ibfk_1`;
ALTER TABLE `logs` ADD CONSTRAINT `logs_user_fk`
FOREIGN KEY (`user_id`) REFERENCES `ab_user`(`id`) ON DELETE SET NULL;
-- Example for dashboard_user table
ALTER TABLE `dashboard_user` DROP FOREIGN KEY `dashboard_user_ibfk_1`;
ALTER TABLE `dashboard_user` ADD CONSTRAINT `dashboard_user_user_fk`
FOREIGN KEY (`user_id`) REFERENCES `ab_user`(`id`) ON DELETE CASCADE;
```
The correct long-term fix would be either:
- Adding `ON DELETE` rules to the Alembic migration that creates these constraints, or
- Having `flask_appbuilder`'s `delete_user()` clean up dependent rows before deleting the user
## Impact
- User deletion via the GUI is **completely broken** on MariaDB
- Affects all Superset installations using MariaDB where users have any activity (logs, queries, dashboards, etc.)
- PostgreSQL may also be affected depending on FK constraint definitions
### Screenshots/recordings
_No response_
### Superset version
6.0.0
### Python version
3.11
### Node version
Not applicable
### Browser
Chrome
### Additional context
_No response_
### Checklist
- [x] I have searched Superset docs and Slack and didn't find a solution to my problem.
- [x] I have searched the GitHub issue tracker and didn't find a similar bug report.
- [x] I have checked Superset's logs for errors and if I found a relevant Python stacktrace, I included it here as text in the "additional context" section.
Contributor guide
Research direction
Start at Flask-AppBuilder's SecurityManager.delete_user() and the Superset Alembic migrations that define the listed user_id foreign keys. Reproduce deletion against MariaDB, then inspect each dependent table's intended SET NULL or CASCADE behavior. Done means GUI deletion succeeds without IntegrityError while audit and ownership data follow the specified retention rules.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, sql, sqlalchemy
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100