Tencent/WeKnora · error

task %s in queue %s cannot be deleted

Error message

task %s in queue %s cannot be deleted

What it means

DeleteRuntimeTask wraps asynq's inspector DeleteTask with an action-permission check. It first resolves the RuntimeTask via GetRuntimeTask and requires that the task's current state allows RuntimeTaskActionDelete. A nil task (not found) or a state that forbids deletion (e.g. the task is currently active) yields this error.

Source

Thrown at internal/router/task_inspector.go:673

	if err != nil {
		return true, err
	}
	if task == nil || !task.Allows(types.RuntimeTaskActionRunNow) {
		return true, fmt.Errorf("task %s in queue %s cannot run now", taskID, queue)
	}
	return true, a.inspector.RunTask(queue, taskID)
}

func (a *asynqTaskInspector) DeleteRuntimeTask(ctx context.Context, queue, taskID string) (bool, error) {
	if a == nil || a.inspector == nil {
		return false, nil
	}
	task, _, err := a.GetRuntimeTask(ctx, queue, taskID)
	if err != nil {
		return true, err
	}
	if task == nil || !task.Allows(types.RuntimeTaskActionDelete) {
		return true, fmt.Errorf("task %s in queue %s cannot be deleted", taskID, queue)
	}
	return true, a.inspector.DeleteTask(queue, taskID)
}

func (a *asynqTaskInspector) ForceDeleteRuntimeTask(ctx context.Context, queue, taskID string) (bool, error) {
	if a == nil || a.inspector == nil {
		return false, nil
	}
	return true, a.inspector.DeleteTask(queue, taskID)
}

// PurgeArchivedRuntimeTasks clears the whole archived (dead-letter) set for one
// queue. asynq's DeleteAllArchivedTasks scopes strictly to the archived list,
// so pending/active/scheduled/retry work is never at risk.
func (a *asynqTaskInspector) PurgeArchivedRuntimeTasks(ctx context.Context, queue string) (int, bool, error) {
	if a == nil || a.inspector == nil {
		return 0, false, nil
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Confirm the task still exists via GetRuntimeTask before deleting and handle the not-found case as success (idempotent delete)
  2. Check task.Allows(types.RuntimeTaskActionDelete) client-side to pre-validate
  3. For tasks in an undeletable active state, wait for completion or use ForceDeleteRuntimeTask
  4. Verify the queue name matches where the task actually lives

Example fix

// before
err := inspector.DeleteRuntimeTask(ctx, queue, taskID) // fails if active or gone
// after
task, _, _ := inspector.GetRuntimeTask(ctx, queue, taskID)
if task == nil { return nil } // already deleted
if task.Allows(types.RuntimeTaskActionDelete) {
    err = inspector.DeleteRuntimeTask(ctx, queue, taskID)
}
Defensive patterns

Strategy: validation

Validate before calling

task, _, err := inspector.GetRuntimeTask(ctx, queue, taskID)
if err != nil { return err }
if task == nil { return nil } // already deleted: treat as idempotent success
if !task.Allows(types.RuntimeTaskActionDelete) { return fmt.Errorf("task %s not deletable", taskID) }

Type guard

func canDelete(t types.RuntimeTask) bool { return t != nil && t.Allows(types.RuntimeTaskActionDelete) }

Try / catch

if err := inspector.DeleteRuntimeTask(ctx, queue, taskID); err != nil {
    if strings.Contains(err.Error(), "cannot be deleted") { /* refresh list; maybe use ForceDeleteRuntimeTask */ }
    return err
}

Prevention

When it happens

Trigger: Calling DeleteRuntimeTask(ctx, queue, taskID) when the taskID does not exist in that queue, or the task is in a state such as active/processed where deletion is disallowed by the RuntimeTask action model.

Common situations: Double-clicking a delete button so the second call targets an already-deleted task; attempting to delete a task that just transitioned to active; deleting from the wrong queue name.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/4ede0732037b67aa. Report an issue: GitHub.