goharbor/harbor · warning · lib/errors.Error
NOT_FOUND
NOT_FOUND
Error message
garbage collection execution %d not found
What it means
GetExecution lists task-framework executions filtered by both ID and VendorType=garbage_collection. Zero matching rows returns NOT_FOUND with the requested id - either the id does not exist at all, or it exists but belongs to a different vendor (e.g. replication), so it is invisible to the GC API.
Source
Thrown at src/controller/gc/controller.go:142
for _, exec := range execs {
executions = append(executions, convertExecution(exec))
}
return executions, nil
}
// GetExecution ...
func (c *controller) GetExecution(ctx context.Context, id int64) (*Execution, error) {
execs, err := c.exeMgr.List(ctx, &q.Query{
Keywords: map[string]any{
"ID": id,
"VendorType": job.GarbageCollectionVendorType,
},
})
if err != nil {
return nil, err
}
if len(execs) == 0 {
return nil, errors.New(nil).WithCode(errors.NotFoundCode).
WithMessagef("garbage collection execution %d not found", id)
}
return convertExecution(execs[0]), nil
}
// GetTask ...
func (c *controller) GetTask(ctx context.Context, id int64) (*Task, error) {
tasks, err := c.taskMgr.List(ctx, &q.Query{
Keywords: map[string]any{
"ID": id,
"VendorType": job.GarbageCollectionVendorType,
},
})
if err != nil {
return nil, err
}
if len(tasks) == 0 {
return nil, errors.New(nil).WithCode(errors.NotFoundCode).View on GitHub (pinned to 7b2fd08cc5)
Solutions
- List executions via GET /api/system/gc?page=1&page_size=10 and use an id from that result.
- If the id looks valid, confirm it is a GC execution (not replication/purge) via the vendor-filtered list.
- Treat 404 as expected for pruned history - fetch the list rather than caching ids.
Example fix
// before
exec, err := gcCtl.GetExecution(ctx, idFromScript)
// after
execs, _, _ := apiClient.ListGCExecutions()
if len(execs) == 0 { /* no GC has run yet */ }
exec, err := gcCtl.GetExecution(ctx, execs[0].ID) Defensive patterns
Strategy: validation
Validate before calling
// resolve ids from the vendor-filtered list before Get:
execs, err := gcCtl.ListExecutions(ctx, &q.Query{Page:1, PageSize:10})
if err != nil || len(execs) == 0 { /* nothing to get */ }
for _, e := range execs { if e.ID == wantID { ok = true } } Try / catch
if _, err := gcCtl.GetExecution(ctx, id); err != nil {
if liberrors.IsErr(err, liberrors.NotFoundCode) {
// stale or wrong-vendor id: refresh from list endpoint
}
return err
} Prevention
- Never hardcode execution ids; always resolve from the list API.
- Poll with the id returned by the trigger call (POST /api/system/gc).
- Expect 404 for pruned history; design polling to end gracefully.
When it happens
Trigger: GET /api/system/gc/{id} with a stale, wrong-type, or invented execution id; execution records pruned by retention; copying an id from the replication execution list into the GC endpoint.
Common situations: Bookmark or script holding an id from before record cleanup; mixing ids between execution APIs; probing after a Harbor DB restore.
Related errors
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/76784d3daf9d5d09.
Report an issue: GitHub.