semaphoreui/semaphore · error

task is not active

Error message

task is not active

What it means

ConfirmTask transitions a pending task to the confirmed state by looking it up in the in-memory task pool. When the task is not in the pool (nil) the comment notes it 'exists in database' but is not active locally — typically already finished, restarted, or evicted — so confirmation is refused with this error.

Solutions

  1. Check the task's current state before confirming; skip confirmation if it already finished
  2. Treat this as a benign race in idempotent clients — log and continue instead of failing hard
  3. Re-run/re-trigger the task if a fresh confirmation cycle is genuinely needed
  4. Verify only one server instance manages the task pool (or use a shared/stateful setup)
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm only while task is pending
if tsk.Status != taskStatusPending { /* skip confirmation */ }

Try / catch

if err := pool.ConfirmTask(taskID, ...); err != nil {
    if strings.Contains(err.Error(), "task is not active") {
        return nil // already finished/rejected; idempotent no-op
    }
    return err
}

Prevention

When it happens

Trigger: Calling ConfirmTask with a task ID whose in-memory representation has been removed: the task already ran/finished, the server restarted losing the pool, or the ID never belonged to an active task on this instance.

Common situations: Confirming a task twice (second call finds nothing active); delayed confirmation after the task timed out or completed; multi-instance setups where the task was scheduled on another node; server restart mid-workflow.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07). Data as JSON: /api/errors/81a56e90d2448484. Report an issue: GitHub.

Appendix: source

Thrown at services/tasks/TaskPool.go:637

	res := proj.MaxParallelTasks > 0 && p.state.ActiveCount(t.Task.ProjectID) >= proj.MaxParallelTasks

	if res {
		return true
	}

	return res
}

func (p *TaskPool) ConfirmTask(targetTask db.Task) error {
	tsk, err := p.GetTask(targetTask.ID)

	if err != nil {
		return err
	}

	if tsk == nil { // task not active, but exists in database
		return fmt.Errorf("task is not active")
	}

	tsk.SetStatus(task_logger.TaskConfirmed)

	return nil
}

func (p *TaskPool) RejectTask(targetTask db.Task) error {
	tsk, err := p.GetTask(targetTask.ID)

	if err != nil {
		return err
	}

	if tsk == nil { // task not active, but exists in database
		return fmt.Errorf("task is not active")
	}

View on GitHub (pinned to 1774ccb71a)