{"record":{"id":"76784d3daf9d5d09","repo":"goharbor/harbor","slug":"not-found-76784d","errorCode":"NOT_FOUND","errorMessage":"garbage collection execution %d not found","messagePattern":"garbage collection execution (.+?) not found","errorType":"http","errorClass":"lib/errors.Error","httpStatus":404,"severity":"warning","filePath":"src/controller/gc/controller.go","lineNumber":142,"sourceCode":"\tfor _, exec := range execs {\n\t\texecutions = append(executions, convertExecution(exec))\n\t}\n\treturn executions, nil\n}\n\n// GetExecution ...\nfunc (c *controller) GetExecution(ctx context.Context, id int64) (*Execution, error) {\n\texecs, err := c.exeMgr.List(ctx, &q.Query{\n\t\tKeywords: map[string]any{\n\t\t\t\"ID\":         id,\n\t\t\t\"VendorType\": job.GarbageCollectionVendorType,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(execs) == 0 {\n\t\treturn nil, errors.New(nil).WithCode(errors.NotFoundCode).\n\t\t\tWithMessagef(\"garbage collection execution %d not found\", id)\n\t}\n\treturn convertExecution(execs[0]), nil\n}\n\n// GetTask ...\nfunc (c *controller) GetTask(ctx context.Context, id int64) (*Task, error) {\n\ttasks, err := c.taskMgr.List(ctx, &q.Query{\n\t\tKeywords: map[string]any{\n\t\t\t\"ID\":         id,\n\t\t\t\"VendorType\": job.GarbageCollectionVendorType,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(tasks) == 0 {\n\t\treturn nil, errors.New(nil).WithCode(errors.NotFoundCode).","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/controller/gc/controller.go#L124-L160","documentation":"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.","triggerScenarios":"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.","commonSituations":"Bookmark or script holding an id from before record cleanup; mixing ids between execution APIs; probing after a Harbor DB restore.","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."],"exampleFix":"// before\nexec, err := gcCtl.GetExecution(ctx, idFromScript)\n\n// after\nexecs, _, _ := apiClient.ListGCExecutions()\nif len(execs) == 0 { /* no GC has run yet */ }\nexec, err := gcCtl.GetExecution(ctx, execs[0].ID)","handlingStrategy":"validation","validationCode":"// resolve ids from the vendor-filtered list before Get:\nexecs, err := gcCtl.ListExecutions(ctx, &q.Query{Page:1, PageSize:10})\nif err != nil || len(execs) == 0 { /* nothing to get */ }\nfor _, e := range execs { if e.ID == wantID { ok = true } }","typeGuard":null,"tryCatchPattern":"if _, err := gcCtl.GetExecution(ctx, id); err != nil {\n    if liberrors.IsErr(err, liberrors.NotFoundCode) {\n        // stale or wrong-vendor id: refresh from list endpoint\n    }\n    return err\n}","preventionTips":["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."],"tags":["garbage-collection","not-found","api","execution"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}