goharbor/harbor · warning · lib/errors.Error
NOT_FOUND
NOT_FOUND
Error message
no schedule is found
What it means
The jobservice schedule controller's Get lists schedules filtered only by the caller-supplied vendorType. If no schedule exists for that vendor (job never scheduled through this API), it returns NOT_FOUND 'no schedule is found' - the expected state before the first Create call for that vendor.
Source
Thrown at src/controller/jobservice/schedule.go:70
queueStatusMgr queuestatus.Manager
}
// NewSchedulerCtrl ...
func NewSchedulerCtrl() SchedulerController {
return &schedulerController{
schedulerMgr: scheduler.New(),
jobServiceRedisClient: jm.JobServiceRedisClient,
queueStatusMgr: queuestatus.Mgr,
}
}
func (s *schedulerController) Get(ctx context.Context, vendorType string) (*scheduler.Schedule, error) {
sch, err := s.schedulerMgr.ListSchedules(ctx, q.New(q.KeyWords{"VendorType": vendorType}))
if err != nil {
return nil, err
}
if len(sch) == 0 {
return nil, errors.New(nil).WithCode(errors.NotFoundCode).WithMessage("no schedule is found")
}
if sch[0] == nil {
return nil, errors.New(nil).WithCode(errors.NotFoundCode).WithMessage("no schedule is found")
}
return sch[0], nil
}
func (s *schedulerController) Create(ctx context.Context, vendorType, cronType, cron, callbackFuncName string,
policy any, extrasParam map[string]any) (int64, error) {
return s.schedulerMgr.Schedule(ctx, vendorType, -1, cronType, cron, callbackFuncName, policy, extrasParam)
}
func (s *schedulerController) Delete(ctx context.Context, vendorType string) error {
return s.schedulerMgr.UnScheduleByVendor(ctx, vendorType, -1)
}
func (s *schedulerController) List(ctx context.Context, query *q.Query) ([]*scheduler.Schedule, error) {
return s.schedulerMgr.ListSchedules(ctx, query)View on GitHub (pinned to 7b2fd08cc5)
Solutions
- Create the schedule for the vendor type first (schedulerController.Create with cron spec).
- Treat 404 as 'not scheduled' and branch accordingly in the client.
- Confirm you are querying the right vendorType string.
Example fix
// before
sch, err := schedCtl.Get(ctx, vendorType)
// after
sch, err := schedCtl.Get(ctx, vendorType)
if liberrors.IsErr(err, liberrors.NotFoundCode) {
_, err = schedCtl.Create(ctx, vendorType, scheduler.Hourly, "0 0 * * * *", callback, nil, nil)
} Defensive patterns
Strategy: fallback
Validate before calling
sch, err := schedCtl.Get(ctx, vendorType)
if liberrors.IsErr(err, liberrors.NotFoundCode) {
sch = nil // interpret as "no schedule for this vendor yet"
} Try / catch
sch, err := s.Get(ctx, vendorType)
if err != nil {
if !liberrors.IsErr(err, liberrors.NotFoundCode) { return nil, err }
_, err = s.Create(ctx, vendorType, scheduler.Daily, "0 0 0 * * *", cb, nil, nil)
if err != nil { return nil, err }
sch, err = s.Get(ctx, vendorType)
} Prevention
- Bootstrap optional vendors with create-if-missing logic.
- Double-check the vendorType string (exact match required).
- Treat 404 as state ('unscheduled'), not as an alert.
When it happens
Trigger: GET on the schedule endpoint for a vendor type (e.g. audit log forwarder, purge jobs) before any schedule was created for it; after the vendor's schedule was deleted.
Common situations: Automation reading schedule state before creating it; feature optional and never enabled; schedule removed by cleanup tooling.
Related errors
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/3d5f6cce01390004.
Report an issue: GitHub.