semaphoreui/semaphore · error

runner registration failed

Error message

runner registration failed

What it means

JobPool.Register failed because tryRegisterRunner did not succeed in registering the runner with the Semaphore server (it retries internally and returns false on exhaustion). The message is deliberately opaque; the server response/log details during registration hold the real reason.

Solutions

  1. Verify the runner registration token in the config is valid and not expired; regenerate it from the server UI if needed.
  2. Check the WebHost/URL in the runner config is reachable from the runner (curl the server API).
  3. Inspect runner logs for the underlying HTTP error from tryRegisterRunner attempts.
  4. Confirm server version and runner version are compatible.
Defensive patterns

Strategy: retry

Validate before calling

resp, err := http.Get(cfg.WebHost + "/api/internal/runners")
if err != nil || resp.StatusCode >= 400 {
    return errors.New("server unreachable or rejecting requests before registration")
}

Try / catch

if err := pool.Register(&configPath); err != nil {
    if strings.Contains(err.Error(), "runner registration failed") {
        backoff := 5 * time.Second
        for i := 0; i < 5; i++ {
            time.Sleep(backoff)
            if err := pool.Register(&configPath); err == nil { break }
            backoff *= 2
        }
    }
}

Prevention

When it happens

Trigger: Register(configFilePath) is called by registerRunner/doRunnerSetup/runRunner and tryRegisterRunner exhausts its attempts — invalid registration token, unreachable server, or the server rejecting the runner.

Common situations: Wrong or expired runner registration token in config; WebHost pointing to the wrong URL or wrong port; TLS/network issues between runner and server; server's registration endpoint disabled.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at services/runners/job_pool.go:211

	return false
}

func (p *JobPool) hasRunningJobs() bool {
	for _, j := range p.snapshotRunningJobs() {
		if !j.getStatus().IsFinished() {
			return true
		}
	}

	return false
}

func (p *JobPool) Register(configFilePath *string) (err error) {

	ok := p.tryRegisterRunner(configFilePath)

	if !ok {
		err = fmt.Errorf("runner registration failed")
		return
	}

	return
}

func (p *JobPool) Unregister() (err error) {

	if util.Config.Runner.Token == "" {
		return fmt.Errorf("runner is not registered")
	}

	url := util.Config.WebHost + "/api/internal/runners"

	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return
	}

View on GitHub (pinned to 1774ccb71a)