goharbor/harbor · error · lib/errors.Error
PRECONDITION
PRECONDITION
Error message
the registry %d is referenced by replication policies, cannot delete it
What it means
First referential check in registry Delete(): replication policies with src_registry_id = id are counted; a count > 0 refuses deletion with PRECONDITION 'the registry %d is referenced by replication policies, cannot delete it'. A registry used as a replication SOURCE cannot be removed while policies depend on it.
Source
Thrown at src/controller/registry/controller.go:142
func (c *controller) Update(ctx context.Context, registry *model.Registry, props ...string) error {
if err := c.validate(ctx, registry); err != nil {
return err
}
return c.regMgr.Update(ctx, registry, props...)
}
func (c *controller) Delete(ctx context.Context, id int64) error {
// referenced by replication policy as source registry
count, err := c.repMgr.Count(ctx, &q.Query{
Keywords: map[string]any{
"src_registry_id": id,
},
})
if err != nil {
return err
}
if count > 0 {
return errors.New(nil).WithCode(errors.PreconditionCode).WithMessagef("the registry %d is referenced by replication policies, cannot delete it", id)
}
// referenced by replication policy as destination registry
count, err = c.repMgr.Count(ctx, &q.Query{
Keywords: map[string]any{
"dest_registry_id": id,
},
})
if err != nil {
return err
}
if count > 0 {
return errors.New(nil).WithCode(errors.PreconditionCode).WithMessagef("the registry %d is referenced by replication policies, cannot delete it", id)
}
// referenced by proxy cache project
count, err = c.proMgr.Count(ctx, &q.Query{
Keywords: map[string]any{
"registry_id": id,
},View on GitHub (pinned to 7b2fd08cc5)
Solutions
- List replication policies and delete or edit those with this registry as source (filter on src_registry_id).
- Repeat the DELETE only when the count is zero.
- Communicate with policy owners before removing shared source registries.
Example fix
# before
DELETE /api/v2/registries/5
# after
GET /api/v2/replication/policies?src_registry_id=5 # find dependents
PUT /api/v2/replication/policies/{pid} # repoint src_registry or
DELETE /api/v2/replication/policies/{pid} # remove policy
DELETE /api/v2/registries/5 Defensive patterns
Strategy: validation
Validate before calling
// count source references before delete:
count, err := repMgr.Count(ctx, q.New(q.KeyWords{"src_registry_id": id}))
if err != nil { return err }
if count > 0 { return fmt.Errorf("%d replication policies use registry %d as source", count, id) }
return regCtl.Delete(ctx, id) Try / catch
if err := regCtl.Delete(ctx, id); err != nil {
if liberrors.IsErr(err, liberrors.PreconditionCode) {
// list policies (src_registry_id=id), delete or repoint, then retry
}
return err
} Prevention
- Run a reference audit (src/dest/project) before decommissioning registries.
- Keep IaC that owns replication policies and registries in one plan.
- Retry the DELETE only after the dependent count is zero.
When it happens
Trigger: DELETE /api/v2/registries/{id} while replication policies pull FROM this registry (it is their src_registry).
Common situations: Decommissioning an upstream registry without checking replication rules; shared registry retired while policies remain.
Related errors
- PRECONDITION
- PRECONDITION
- Only can have one trace exporter at a time
- Error: storage driver %s is not supported, only the followin
- Error: storage driver %s is not supported, only the followin
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/2e15bebc33401e8e.
Report an issue: GitHub.