goharbor/harbor · info · lib/errors.Error
unknown status
Error message
unknown status
What it means
PeriodicHealthChecker wraps a checker with a background ticker and deliberately initializes status to errors.New("unknown status") so the component does not look healthy before the first Check() completes. The value is an internal sentinel (no error code); it surfaces through /api/v2/health style component status until the first tick overwrites it.
Source
Thrown at src/controller/health/checker.go:97
u.Lock()
defer u.Unlock()
return u.status
}
func (u *updater) update(status error) {
u.Lock()
defer u.Unlock()
u.status = status
}
// PeriodicHealthChecker implements a Checker to check status periodically
func PeriodicHealthChecker(checker health.Checker, period time.Duration) health.Checker {
u := &updater{
// init the "status" as "unknown status" error to avoid returning nil error(which means healthy)
// before the first health check request finished
status: errors.New("unknown status"),
}
go func() {
ticker := time.NewTicker(period)
for {
u.update(checker.Check())
<-ticker.C
}
}()
return u
}
func coreHealthChecker() health.Checker {
return health.CheckFunc(func() error {
return nil
})
}View on GitHub (pinned to 7b2fd08cc5)
Solutions
- Wait one check period (or add a startup probe / initialDelay) before treating the component as failed.
- Verify the underlying dependency the checker contacts is reachable so the first tick can succeed.
- Treat 'unknown status' as not-yet-ready, distinct from unhealthy, in probe logic.
Example fix
// before
if err := component.Health(); err != nil { restart() }
// after
if err := component.Health(); err != nil {
if err.Error() == "unknown status" { waitOnePeriod(); continue }
restart()
} Defensive patterns
Strategy: retry
Validate before calling
// probe readiness before acting on health status:
func ready(h health.Checker, period time.Duration) bool {
deadline := time.Now().Add(2 * period)
for time.Now().Before(deadline) {
if err := h.Check(); err == nil || err.Error() != "unknown status" { return true }
time.Sleep(time.Second)
}
return false
} Type guard
func isUnknownStatus(err error) bool {
return err != nil && err.Error() == "unknown status"
} Try / catch
if err := comp.Check(); err != nil {
if err.Error() == "unknown status" {
// not yet initialized: back off one period and re-check
time.Sleep(period)
err = comp.Check()
}
if err != nil { /* now a real failure */ }
} Prevention
- Give components a startup grace window (startup probe / initialDelay) longer than the check period.
- Ensure the checked dependency is reachable so the first tick succeeds.
- Distinguish 'unknown' from 'unhealthy' in alerting to avoid restart storms.
When it happens
Trigger: Querying component health within one check period of process start; the wrapped Check() blocking forever so the status never updates; a very long period configured.
Common situations: Harbor core/jobservice just restarted and orchestrators probe health immediately; the checked dependency (DB, registry) is slow to accept connections; probes with no startup grace window.
Related errors
- NOT_FOUND
- no worker worker is configured
- URL of redis worker is empty
- invalid redis URL
- namespace of redis worker is required
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/702b17e8084f0e9c.
Report an issue: GitHub.