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

  1. 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.
  2. Only expose Abort in the UI for task types known to register handlers; derive that from task.properties.is_abortable.
  3. If aborting legacy tasks, first check properties_dict.get('is_abortable') is True and surface 'not abortable' rather than issuing the call.
  4. 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

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


AI-assisted analysis of apache/superset@f4587218dd (2026-08-14). Data as JSON: /api/errors/2b6f0b0547dfcbe2. Report an issue: GitHub.