apache/superset · error · TaskNotAbortableError
Task {task_uuid} is in progress but has not registered an ab
Error message
Task {task_uuid} is in progress but has not registered an abort handler (is_abortable is not true) What it means
Raised by TaskDAO's abort path when a task is TaskStatus.IN_PROGRESS but its properties_dict does not have is_abortable set to True. Abortability is opt-in: the component that starts a long-running task must register an abort handler and set the is_abortable property; aborting an in-progress task without that registration cannot work, so TaskNotAbortableError (status 400) is raised. PENDING tasks are aborted directly and terminal states are filtered out beforehand, so this error is specific to running-but-unabortable tasks.
Source
Thrown at superset/daos/tasks.py:240
# Already aborting - idempotent success
if task.status == TaskStatus.ABORTING.value:
logger.info("Task %s is already aborting", task_uuid)
return task
# Already finished - cannot abort
if task.status not in ABORTABLE_STATES:
return None
# PENDING: Go directly to ABORTED
if task.status == TaskStatus.PENDING.value:
task.set_status(TaskStatus.ABORTED)
logger.info("Aborted pending task: %s (scope: %s)", task_uuid, task.scope)
return task
# IN_PROGRESS: Check if abortable
if task.status == TaskStatus.IN_PROGRESS.value:
if task.properties_dict.get("is_abortable") is not True:
raise TaskNotAbortableError(
f"Task {task_uuid} is in progress but has not registered "
"an abort handler (is_abortable is not true)"
)
# Transition to ABORTING (not ABORTED yet)
task.set_status(TaskStatus.ABORTING)
db.session.merge(task)
logger.info("Set task %s to ABORTING (scope: %s)", task_uuid, task.scope)
# NOTE: publish_abort is NOT called here - caller handles it after commit
# This prevents race conditions where listeners check DB before commit
return task
return None
# Subscription management methods
View on GitHub (pinned to f4587218dd)
Solutions
- In the task executor, register the abort handler and set properties {'is_abortable': True} (via update_properties) before/when transitioning the task to IN_PROGRESS.
- Only expose Abort in the UI for task types known to register handlers; derive that from task.properties.is_abortable.
- If aborting legacy tasks, first check properties_dict.get('is_abortable') is True and surface 'not abortable' rather than issuing the call.
- Handle TaskNotAbortableError (400) as non-retryable — retrying will not register a handler.
Example fix
# before
TaskDAO.abort_task(task_uuid) # IN_PROGRESS without is_abortable -> TaskNotAbortableError 400
# after
# executor side: register abortability before long work
task.update_properties({'is_abortable': True})
register_abort_handler(task_uuid, handler)
task.set_status(TaskStatus.IN_PROGRESS)
# caller side: guard before aborting
props = TaskDAO.get_task(task_uuid).properties_dict
if props.get('is_abortable') is True:
TaskDAO.abort_task(task_uuid) Defensive patterns
Strategy: validation
Validate before calling
task = TaskDAO.get_task(task_uuid)
props = task.properties_dict if task else {}
if task and task.status == 'IN_PROGRESS' and props.get('is_abortable') is not True:
raise ValidationError('task is running but not abortable') # block before calling abort Try / catch
from superset.commands.tasks.exceptions import TaskNotAbortableError
try:
TaskDAO.abort_task(task_uuid)
except TaskNotAbortableError:
# 400 and non-retryable: surface 'cannot abort' and let the task finish/timeout
notify(f'task {task_uuid} cannot be aborted') Prevention
- Register abort handlers and set is_abortable=True before moving tasks to IN_PROGRESS.
- Gate Abort buttons on properties_dict.is_abortable, not on task status alone.
- Treat TaskNotAbortableError as non-retryable; fix the executor's registration instead.
When it happens
Trigger: Calling the task-abort API/DAO for an IN_PROGRESS task whose executor never called the equivalent of set_properties(is_abortable=True) with a registered handler; aborting tasks created by older code paths or external producers that predate the abort-handler protocol; racing an abort against a task that is between IN_PROGRESS and handler registration.
Common situations: Adopting the tasks framework for a new background job and skipping abort-handler registration; version skew where the UI shows an Abort button for task types that do not support it; third-party task producers writing rows with status IN_PROGRESS but no properties.
Related errors
- user_id is required for private tasks
- Invalid filter: column '%s' does not exist on %s
- Operator '{operator_enum.value}' on relationship column '{co
- created_by_fk_or_editor only supports 'eq'; got '{c.opr}'
- created_by_fk_or_editor only supports 'eq'; got '{c.opr}'
AI-assisted analysis of apache/superset@f4587218dd (2026-08-14).
Data as JSON: /api/errors/2b6f0b0547dfcbe2.
Report an issue: GitHub.