semaphoreui/semaphore · error

503 Service Unavailable

Error message

503 Service Unavailable

What it means

Returned by the Metrics ServeHTTP handler in pkg/metrics/metrics.go when the receiver is nil or its embedded prometheus handler was never initialised (e.g. the Metrics object was constructed without registering a registry). It is a guard that degrades gracefully: instead of panicking on scrape, it answers HTTP 503 so the scraper knows metrics are temporarily unavailable rather than silently scraping an empty page.

Solutions

  1. Ensure metrics.New()/registration runs before the handler is mounted on the HTTP mux
  2. Check that the Metrics value is not a nil pointer (a common cause is returning a nil *Metrics from a failed constructor and then using it as a handler)
  3. Wire a live *prometheus.Registry into the handler during service startup so ServeHTTP never sees a nil inner handler
  4. Scrapers should treat 503 from this endpoint as 'metrics not ready' and retry after startup completes
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at pkg/metrics/metrics.go:72 when the library encounters an invalid state.

Common situations: See trigger scenarios.

Understand the failure class


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

Appendix: source

Thrown at pkg/metrics/metrics.go:72

		return
	}

	if oldStatus == task_logger.TaskRunningStatus {
		m.tasksRunning.Dec()
	}

	if newStatus == task_logger.TaskRunningStatus {
		m.tasksRunning.Inc()
	}

	if newStatus.IsFinished() && !oldStatus.IsFinished() {
		m.tasksTotal.WithLabelValues(string(newStatus)).Inc()
	}
}

func (m *Metrics) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if m == nil || m.handler == nil {
		http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
		return
	}
	m.handler.ServeHTTP(w, r)
}

View on GitHub (pinned to 1774ccb71a)