semaphoreui/semaphore · error
task not found
Error message
task not found
What it means
RemoteJob.Run looks up the task by ID before executing it remotely; if the database lookup succeeds but returns no task, Run fails with 'task not found'. This protects against running jobs for tasks that were deleted or belong to another project while the job was queued.
Solutions
- Check the task still exists (GET /project/{project_id}/tasks/{task_id}) before/while the job runs
- Do not delete tasks while their jobs are queued; cancel the job first
- Verify all server replicas connect to the same primary database
- Confirm the task ID used by the job scheduler matches a real task
Defensive patterns
Strategy: try-catch
Validate before calling
tsk, err := dbStore.GetTask(projectID, taskID)
if err != nil || tsk == nil { /* do not schedule the job */ } Try / catch
if err := job.Run(...); err != nil {
if strings.Contains(err.Error(), "task not found") {
log.Printf("task %d vanished before run; skipping", taskID)
return nil // treat as benign
}
return err
} Prevention
- Do not delete tasks while their remote jobs are queued
- Use cascading deletes so job records die with their tasks
- Verify all replicas point at the same database
When it happens
Trigger: Calling Run for a task ID that no longer exists in the database — the task was deleted between scheduling and execution, the ID is wrong, or the DB connection points to a different/rolled-back database.
Common situations: Task canceled/deleted while a remote job was still pending; stale job records replayed after a database restore; server replicas pointing at different databases; passing an incorrect task ID to the internal job runner.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07).
Data as JSON: /api/errors/c6e17c5c9d076a6b.
Report an issue: GitHub.
Appendix: source
Thrown at services/tasks/RemoteJob.go:142
if !r.IsOnline(now, offlineTimeout) {
continue
}
if n := busyTasks(r.ID); n < r.MaxParallelTasks || r.MaxParallelTasks == 0 {
return r
}
}
return nil
}
func (t *RemoteJob) Run(username string, incomingVersion *string, alias string) (err error) {
tsk, err := t.taskPool.GetTask(t.Task.ID)
if err != nil {
return
}
if tsk == nil {
return fmt.Errorf("task not found")
}
tsk.IncomingVersion = incomingVersion
tsk.Username = username
tsk.Alias = alias
t.taskPool.state.UpdateRuntimeFields(tsk)
var runners []db.Runner
tagFilterMode := db.RunnerFilterTagCompleteMatch
if t.RunnerTag == nil {
tagFilterMode = db.RunnerFilterIsDefault
}
var projectRunners []db.Runner
projectRunners, err = t.taskPool.store.GetRunners(t.Task.ProjectID, true, tagFilterMode, t.RunnerTag)
if err != nil {
return
}View on GitHub (pinned to 1774ccb71a)