goharbor/harbor · error
nil stats body
Error message
nil stats body
What it means
job.Stats.Validate (src/jobservice/job/models.go:118) rejects stats lacking the embedded Info object (JSON 'info'). Stats records are persisted to the worker backend and validated on creation/read; a payload without 'info' means the record was truncated, corrupt, or hand-built incorrectly.
Source
Thrown at src/jobservice/job/models.go:118
// StatusChange is designed for reporting the status change via hook.
type StatusChange struct {
JobID string `json:"job_id"`
Status string `json:"status"`
CheckIn string `json:"check_in,omitempty"`
Metadata *StatsInfo `json:"metadata,omitempty"`
}
// SimpleStatusChange only keeps job ID and the target status
type SimpleStatusChange struct {
JobID string `json:"job_id"`
TargetStatus string `json:"target_status"`
Revision int64 `json:"revision"`
}
// Validate the job stats
func (st *Stats) Validate() error {
if st.Info == nil {
return errors.New("nil stats body")
}
if utils.IsEmptyStr(st.Info.JobID) {
return errors.New("missing job ID in job stats")
}
if utils.IsEmptyStr(st.Info.JobName) {
return errors.New("missing job name in job stats")
}
if utils.IsEmptyStr(st.Info.JobKind) {
return errors.New("missing job name in job stats")
}
if st.Info.JobKind != KindGeneric &&
st.Info.JobKind != KindPeriodic &&
st.Info.JobKind != KindScheduled {
return errors.Errorf("job kind is not supported: %s", st.Info.JobKind)View on GitHub (pinned to 7b2fd08cc5)
Solutions
- When creating stats, always populate Info with job_id, job_name, and job_kind
- For corrupt persisted stats, delete/recreate the job entry rather than bypassing validation
- Keep producer and consumer Harbor versions aligned on the job.Stats schema
Example fix
// before
st := &job.Stats{}
// after
st := &job.Stats{
Info: &job.StatsInfo{
JobID: "ju-1234",
JobName: "GARBAGE_COLLECTION",
JobKind: job.KindGeneric,
},
} Defensive patterns
Strategy: type-guard
Validate before calling
if err := st.Validate(); err != nil {
return err // fail before persisting or forwarding stats
} Type guard
func hasStatsInfo(st *job.Stats) bool {
return st != nil && st.Info != nil
} Prevention
- Populate Info (job_id, job_name, job_kind) whenever constructing job.Stats
- Call Stats.Validate() before persisting or forwarding stats
- Do not share a Redis job namespace across Harbor versions
When it happens
Trigger: json.Unmarshal of a payload like {} or {"revision":1} into job.Stats followed by Validate; a manager reading a Redis/DB stats entry whose info JSON was written by an incompatible Harbor version.
Common situations: Harbor version upgrades with stats schema drift; sharing a Redis instance across Harbor versions; manually crafted test fixtures; partially migrated job records.
Related errors
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/8a5df1d2248dbc74.
Report an issue: GitHub.