semaphoreui/semaphore · error

no runners available

Error message

no runners available

What it means

RemoteJob.Run queries the database for runners eligible to execute the task (matching project/environment and enabled). If the result set is empty, no execution target exists and Run aborts with 'no runners available'.

Solutions

  1. Register and start at least one runner for the project (semaphore runner register/start)
  2. Check runner status in the UI/DB — re-enable disabled runners and fix offline ones (network, token, heartbeat)
  3. Ensure the task's environment matches an environment the runner is configured for
  4. Check runner logs for connectivity/token errors and re-register with a fresh token if needed
Defensive patterns

Strategy: try-catch

Validate before calling

runners, err := dbStore.GetRunners(projectID)
ready := 0
for _, r := range runners { if r.Active { ready++ } }
if ready == 0 { /* do not schedule; alert */ }

Try / catch

if err := job.Run(...); err != nil {
    if strings.Contains(err.Error(), "no runners available") {
        // re-queue with delay and alert operators
    }
}

Prevention

When it happens

Trigger: Running a remote task when every registered runner is disabled, offline/dead (failed heartbeat), filtered out by the task's environment, or simply when no runner is registered at all for the project.

Common situations: Fresh install where no runner was ever registered; all runners lost connectivity (network/firewall, expired runner token); runner disabled for maintenance; task assigned an environment no runner serves.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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

Appendix: source

Thrown at services/tasks/RemoteJob.go:176

	if err != nil {
		return
	}

	var globalRunners []db.Runner
	globalRunners, err = t.taskPool.store.GetAllRunners(true, true, tagFilterMode, t.RunnerTag)
	if err != nil {
		return
	}

	runners = append(runners, shuffleRunners(projectRunners)...)
	runners = append(runners, shuffleRunners(globalRunners)...)

	if err != nil {
		return
	}

	if len(runners) == 0 {
		err = fmt.Errorf("no runners available")
		return
	}

	runner := selectRunner(
		runners,
		tz.Now(),
		util.Config.RunnersOfflineTimeout(),
		t.taskPool.GetNumberOfRunningTasksOfRunner)

	if runner == nil {
		err = ErrAllRunnersBusy
		return
	}

	err = callRunnerWebhook(runner, tsk, "start")

	if err != nil {
		return

View on GitHub (pinned to 1774ccb71a)