goharbor/harbor · error

missing job ID in job stats

Error message

missing job ID in job stats

What it means

job.Stats.Validate (src/jobservice/job/models.go:122) requires Info.JobID to be non-empty. The ID is the primary key used later to retrieve, stop, and retry the job, so stats without it are unusable and rejected.

Solutions

  1. Always set Info.JobID from the job UUID generated at submission before saving stats
  2. Check the serialized JSON uses the exact 'job_id' key
  3. Fix or discard the producer that wrote stats without an ID

Example fix

// before
Info: &job.StatsInfo{JobName: "REPLICATION"}
// after
Info: &job.StatsInfo{
    JobID:   "ju-1234",
    JobName: "REPLICATION",
}
Defensive patterns

Strategy: type-guard

Validate before calling

if err := st.Validate(); err != nil {
    return err // reject stats without a job ID before use
}

Type guard

func hasStatsJobID(st *job.Stats) bool {
    return st != nil && st.Info != nil && strings.TrimSpace(st.Info.JobID) != ""
}

Prevention

When it happens

Trigger: Building job.Stats from a struct where the generated job UUID was never assigned; deserializing a stats payload whose info.job_id is missing or empty.

Common situations: Producers ignoring the ID returned at submission time; JSON key mismatches ('job_id' vs 'jobId'); test fixtures with placeholder empty IDs.

Related errors


AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16). Data as JSON: /api/errors/41983a99cd90f46f. Report an issue: GitHub.

Appendix: source

Thrown at src/jobservice/job/models.go:122

	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)
	}

	status := Status(st.Info.Status)
	if err := status.Validate(); err != nil {

View on GitHub (pinned to 7b2fd08cc5)