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
- Verify the runner registration token in the config is valid and not expired; regenerate it from the server UI if needed.
- Check the WebHost/URL in the runner config is reachable from the runner (curl the server API).
- Inspect runner logs for the underlying HTTP error from tryRegisterRunner attempts.
- 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
- Verify the registration token before starting the runner.
- Health-check the server URL from the runner host before launch.
- Keep runner and server versions in sync.
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
- Unauthorized
- You must be signed in to link an external account.
- OIDC sign-in failed: could not find or create the user…
- Empty token
- unknown runner executor type
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)