goharbor/harbor · error · lib/errors.Error
VIOLATE_FOREIGN_KEY_CONSTRAINT
VIOLATE_FOREIGN_KEY_CONSTRAINT
Error message
the deleting artifact is referenced by others
What it means
deleteDeeply refuses to delete an artifact that other artifacts reference: it lists references where ChildID equals the artifact id (parents such as an OCI image index, Docker manifest list, or CNAB bundle containing it), and when the artifact is being deleted directly as a root it returns an error mapped to ViolateForeignKeyConstraint rather than leaving dangling references. Children reached through recursion are silently skipped instead.
Source
Thrown at src/controller/artifact/controller.go:382
return err
}
// the child artifact is referenced by some tags, skip
if !isRoot && len(art.Tags) > 0 {
return nil
}
parents, err := c.artMgr.ListReferences(ctx, &q.Query{
Keywords: map[string]any{
"ChildID": id,
},
})
if err != nil {
return err
}
if len(parents) > 0 {
// the root artifact is referenced by other artifacts
if isRoot {
return errors.New(nil).WithCode(errors.ViolateForeignKeyConstraintCode).
WithMessage("the deleting artifact is referenced by others")
}
// the child artifact is referenced by other artifacts, skip
return nil
}
if isAccessory {
if err := c.accessoryMgr.DeleteAccessories(ctx, q.New(q.KeyWords{"ArtifactID": art.ID, "Digest": art.Digest})); err != nil && !errors.IsErr(err, errors.NotFoundCode) {
return err
}
}
// delete accessories if contains any
for _, acc := range art.Accessories {
// only hard ref accessory should be removed
if acc.IsHard() {
// if this acc artifact has parent(is child), set isRoot to false
parents, err := c.artMgr.ListReferences(ctx, &q.Query{View on GitHub (pinned to 7b2fd08cc5)
Solutions
- Delete the parent artifact (the index or bundle digest) — Harbor recursively deletes unreferenced children
- Find the parents first: fetch the artifact with references to see which index contains it
- If you only want the tag gone, delete the tag rather than the artifact
- Re-check via the API that the artifact has no references before issuing DELETE
Example fix
# before: deleting a child manifest of a multi-arc index curl -X DELETE .../artifacts/sha256:child-digest # 400: referenced by others # after: delete the parent index, children are removed recursively curl -X DELETE .../artifacts/sha256:index-digest
Defensive patterns
Strategy: try-catch
Try / catch
if err := artifactCtl.Delete(ctx, art.ID); err != nil {
if errors.IsErr(err, errors.ViolateForeignKeyConstraintCode) {
// this digest is a child of an index/bundle: fetch its parents and delete those instead
}
return err
} Prevention
- Always delete the top-level index or bundle digest, not per-arch children
- Inspect an artifact's references before deleting it
- Delete tags when you only want to untag, keeping the artifact
When it happens
Trigger: DELETE /api/v2.0/.../artifacts/{digest} on a manifest that is a child of a multi-arch index or CNAB bundle; deleting an in-use per-arch image before its index.
Common situations: Multi-arch images (deleting a single-arch manifest instead of the index), CNAB bundles referencing component images, cleanup jobs trying to remove shared children directly.
Related errors
- NOT_FOUND
- BAD_REQUEST
- purge upload age should set with with nh, n is the number of
- invalid json request
- REQUEST_ENTITY_TOO_LARGE
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/d054a1cf044265a7.
Report an issue: GitHub.