{"record":{"id":"d054a1cf044265a7","repo":"goharbor/harbor","slug":"violate-foreign-key-constraint","errorCode":"VIOLATE_FOREIGN_KEY_CONSTRAINT","errorMessage":"the deleting artifact is referenced by others","messagePattern":"the deleting artifact is referenced by others","errorType":"error_code","errorClass":"lib/errors.Error","httpStatus":412,"severity":"error","filePath":"src/controller/artifact/controller.go","lineNumber":382,"sourceCode":"\t\treturn err\n\t}\n\n\t// the child artifact is referenced by some tags, skip\n\tif !isRoot && len(art.Tags) > 0 {\n\t\treturn nil\n\t}\n\tparents, err := c.artMgr.ListReferences(ctx, &q.Query{\n\t\tKeywords: map[string]any{\n\t\t\t\"ChildID\": id,\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(parents) > 0 {\n\t\t// the root artifact is referenced by other artifacts\n\t\tif isRoot {\n\t\t\treturn errors.New(nil).WithCode(errors.ViolateForeignKeyConstraintCode).\n\t\t\t\tWithMessage(\"the deleting artifact is referenced by others\")\n\t\t}\n\t\t// the child artifact is referenced by other artifacts, skip\n\t\treturn nil\n\t}\n\n\tif isAccessory {\n\t\tif err := c.accessoryMgr.DeleteAccessories(ctx, q.New(q.KeyWords{\"ArtifactID\": art.ID, \"Digest\": art.Digest})); err != nil && !errors.IsErr(err, errors.NotFoundCode) {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// delete accessories if contains any\n\tfor _, acc := range art.Accessories {\n\t\t// only hard ref accessory should be removed\n\t\tif acc.IsHard() {\n\t\t\t// if this acc artifact has parent(is child), set isRoot to false\n\t\t\tparents, err := c.artMgr.ListReferences(ctx, &q.Query{","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/controller/artifact/controller.go#L364-L400","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before: deleting a child manifest of a multi-arc index\ncurl -X DELETE .../artifacts/sha256:child-digest   # 400: referenced by others\n# after: delete the parent index, children are removed recursively\ncurl -X DELETE .../artifacts/sha256:index-digest","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := artifactCtl.Delete(ctx, art.ID); err != nil {\n    if errors.IsErr(err, errors.ViolateForeignKeyConstraintCode) {\n        // this digest is a child of an index/bundle: fetch its parents and delete those instead\n    }\n    return err\n}","preventionTips":["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"],"tags":["go","harbor","api","artifact","delete","foreign-key","oci-index"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}