goharbor/harbor · error · github.com/goharbor/harbor/src/lib/errors.Error
NOT_FOUND
NOT_FOUND
Error message
webhook task %d not found
What it means
The webhook controller's GetTask (src/controller/webhook/controller.go:148) lists tasks by ID filtered to webhook vendor types; zero matches returns NOT_FOUND (HTTP 404). GetTaskLog raises the same error because it first verifies the task exists and belongs to a webhook.
Source
Thrown at src/controller/webhook/controller.go:148
return c.taskMgr.Count(ctx, buildTaskQuery(execID, query))
}
func (c *controller) ListTasks(ctx context.Context, execID int64, query *q.Query) ([]*task.Task, error) {
return c.taskMgr.List(ctx, buildTaskQuery(execID, query))
}
func (c *controller) GetTask(ctx context.Context, taskID int64) (*task.Task, error) {
query := q.New(q.KeyWords{
"id": taskID,
"vendor_type": webhookJobVendors,
})
tasks, err := c.taskMgr.List(ctx, query)
if err != nil {
return nil, err
}
if len(tasks) == 0 {
return nil, errors.New(nil).WithCode(errors.NotFoundCode).
WithMessagef("webhook task %d not found", taskID)
}
return tasks[0], nil
}
func (c *controller) GetTaskLog(ctx context.Context, taskID int64) ([]byte, error) {
// ensure the webhook task exist
_, err := c.GetTask(ctx, taskID)
if err != nil {
return nil, err
}
return c.taskMgr.GetLog(ctx, taskID)
}
func buildExecutionQuery(policyID int64, query *q.Query) *q.Query {
query = q.MustClone(query)
query.Keywords["vendor_type"] = webhookJobVendorsView on GitHub (pinned to 7b2fd08cc5)
Solutions
- List tasks for the execution first and use an ID from that list
- Confirm the ID is a webhook task ID, not an execution ID or a replication task ID
- Treat 404 as terminal - the task log is gone; enable webhook debug logging earlier next time
Example fix
// before
log, err := webhookCtl.GetTaskLog(ctx, 888) // 404
// after
tasks, _ := webhookCtl.ListTasks(ctx, q.New(q.KeyWords{"ExecutionID": execID}))
for _, t := range tasks {
log, err := webhookCtl.GetTaskLog(ctx, t.ID)
...
} Defensive patterns
Strategy: validation
Validate before calling
tasks, err := webhookCtl.ListTasks(ctx, q.New(q.KeyWords{\"ExecutionID\": execID}))
if err != nil { return err }
for _, t := range tasks {
if t.ID == taskID {
// safe to fetch log
}
} Type guard
func isWebhookTaskNotFound(err error) bool {
return errors.IsNotFoundErr(err) || errors.IsErr(err, errors.NotFoundCode)
} Try / catch
log, err := webhookCtl.GetTaskLog(ctx, taskID)
if err != nil {
if errors.IsNotFoundErr(err) {
// task of another vendor type or pruned; stop and report
}
return err
} Prevention
- Only use task IDs returned by the webhook execution's task list
- Do not reuse IDs from other job vendors (replication/scan)
- Handle 404 as permanent; cache logs you need beyond the retention window
When it happens
Trigger: GET webhook task or task-log endpoints with a task ID that doesn't exist, belongs to another job vendor type (replication, scan, GC), or was cleaned up after its retention window.
Common situations: Dashboards caching task IDs from old webhook executions; passing the webhook execution ID instead of the task ID; task records pruned by jobservice log cleanup.
Related errors
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/79af0529a1ea2545.
Report an issue: GitHub.