apache/superset · error · DAODeleteFailedError
Failed to remove subscription for task {task_id}, user {user
Error message
Failed to remove subscription for task {task_id}, user {user_id} What it means
Raised by TaskDAO when removing a subscriber from an alert/report task fails. The DAO performs the delete + flush inside a try block; any unexpected exception (DB error, stale task row, session issue) is re-wrapped as DAODeleteFailedError with the message naming the task_id and user_id. Only the two expected not-found cases raise it directly; everything else lands in the generic except.
Source
Thrown at superset/daos/tasks.py:331
if not subscription:
return None
try:
db.session.delete(subscription)
db.session.flush()
logger.info("Removed subscriber %s from task %s", user_id, task_id)
# Return the updated task
task = cls.find_by_id(task_id, skip_base_filter=True)
if task:
db.session.refresh(task) # Ensure subscribers list is fresh
return task
except DAODeleteFailedError:
raise
except Exception as ex:
raise DAODeleteFailedError(
f"Failed to remove subscription for task {task_id}, user {user_id}"
) from ex
@classmethod
def set_properties_and_payload(
cls,
task_uuid: UUID,
properties: TaskProperties | None = None,
payload: dict[str, Any] | None = None,
) -> bool:
"""
Perform a zero-read SQL UPDATE on properties and/or payload columns.
This method directly writes the provided values without reading first.
The caller (TaskContext) is responsible for maintaining the authoritative
cached state and passing complete values to write.
This method is designed for internal task updates (progress, is_abortable)View on GitHub (pinned to f4587218dd)
Solutions
- Check the chained cause (ex.__cause__) in logs — the original exception says whether it is a connectivity issue, integrity error, or missing row.
- Verify the task_id still exists (TaskDAO.find_by_id) and the user is currently in its subscribers list before retrying the removal.
- If it is a connection issue, fix the metadata DB session/pool config (SQLALCHEMY_DATABASE_URI pool_pre_ping, pool_recycle) and retry the API call.
- For race conditions (row already gone), treat the 4xx response as success — the end state (user not subscribed) is already achieved.
Example fix
// before
task = TaskDAO.remove_subscriber(task_id, user_id)
// after
task = TaskDAO.remove_subscriber(task_id, user_id) # may raise DAODeleteFailedError
# caller:
try:
TaskDAO.remove_subscriber(task_id, user_id)
except DAODeleteFailedError:
current = TaskDAO.find_by_id(task_id, skip_base_filter=True)
if current and user_id in [u.id for u in current.owners]:
raise # real failure
# else: already unsubscribed, treat as done Defensive patterns
Strategy: try-catch
Validate before calling
from superset.daos.task import TaskDAO
task = TaskDAO.find_by_id(task_id, skip_base_filter=True)
if task and any(u.id == user_id for u in task.owners):
TaskDAO.remove_subscriber(task_id, user_id) Try / catch
from superset.daos.exceptions import DAODeleteFailedError
try:
TaskDAO.remove_subscriber(task_id, user_id)
except DAODeleteFailedError as ex:
logger.warning("unsubscribe failed: %s", ex, exc_info=ex.__cause__)
# idempotent recovery: verify end state
task = TaskDAO.find_by_id(task_id, skip_base_filter=True)
if task and any(u.id == user_id for u in task.owners):
raise Prevention
- Check the subscriber relationship exists before issuing the delete.
- Make unsubscribe actions idempotent in the UI/API layer (404 or already-removed treated as success).
- Keep metadata DB connections healthy (pool_pre_ping/pool_recycle) to avoid flush failures.
When it happens
Trigger: DELETE call to remove a user's subscription from a report/alert (TaskDAO.remove_subscriber / the REST endpoint that calls it) where db.session.flush() or the preceding delete raises: task UUID deleted concurrently, metadata DB connection dropped mid-transaction, or a subscriber row already removed by a racing request.
Common situations: Two browser tabs unfollowing the same report simultaneously; metadata database (SQLAlchemy session) in a bad state after a long idle connection; operating on a task that was just deleted by an admin.
Related errors
- Database not found
- user_id is required for private tasks
- Task {task_uuid} is in progress but has not registered an ab
- Error: %(error)s
- CSS template not found.
AI-assisted analysis of apache/superset@f4587218dd (2026-08-14).
Data as JSON: /api/errors/a80ddc46a4b11189.
Report an issue: GitHub.