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

  1. List executions via GET /api/system/gc?page=1&page_size=10 and use an id from that result.
  2. If the id looks valid, confirm it is a GC execution (not replication/purge) via the vendor-filtered list.
  3. 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

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.