{"record":{"id":"af786e2277e9abb4","repo":"goharbor/harbor","slug":"not-found","errorCode":"NOT_FOUND","errorMessage":"artifact %s:%s not found","messagePattern":"artifact (.+?):(.+?) not found","errorType":"error_code","errorClass":"lib/errors.Error","httpStatus":404,"severity":"error","filePath":"src/controller/artifact/controller.go","lineNumber":338,"sourceCode":"\treturn c.assembleArtifact(ctx, art, option), nil\n}\n\nfunc (c *controller) getByTag(ctx context.Context, repository, tag string, option *Option) (*Artifact, error) {\n\trepo, err := c.repoMgr.GetByName(ctx, repository)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttags, err := c.tagCtl.List(ctx, &q.Query{\n\t\tKeywords: map[string]any{\n\t\t\t\"RepositoryID\": repo.RepositoryID,\n\t\t\t\"Name\":         tag,\n\t\t},\n\t}, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(tags) == 0 {\n\t\treturn nil, errors.New(nil).WithCode(errors.NotFoundCode).\n\t\t\tWithMessagef(\"artifact %s:%s not found\", repository, tag)\n\t}\n\treturn c.Get(ctx, tags[0].ArtifactID, option)\n}\n\nfunc (c *controller) Delete(ctx context.Context, id int64) error {\n\taccs, err := c.accessoryMgr.List(ctx, q.New(q.KeyWords{\"ArtifactID\": id}))\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn orm.WithTransaction(func(ctx context.Context) error {\n\t\treturn c.deleteDeeply(ctx, id, true, len(accs) > 0)\n\t})(orm.SetTransactionOpNameToContext(ctx, \"tx-delete-artifact-delete\"))\n}\n\n// \"isRoot\" is used to specify whether the artifact is the root parent artifact\n// the error handling logic for the root parent artifact and others is different\n// \"isAccessory\" is used to specify whether the artifact is an accessory.","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/controller/artifact/controller.go#L320-L356","documentation":"getByTag resolves a tag reference for the artifact API: it loads the repository, queries tags by RepositoryID and Name, and when zero tags match it returns NotFound with 'artifact repo:tag not found'. It is reached via GetByReference whenever the reference does not parse as a digest — i.e., every GET-artifact call addressed by tag.","triggerScenarios":"GET /api/v2.0/projects/{project}/repositories/{repo}/artifacts/{tag} where that tag does not exist in that repository: never created, deleted, untagged, mistyped, or the repository name containing '/' was not double-URL-encoded so the wrong repo is looked up.","commonSituations":"UI or automation refreshing a tag that was deleted concurrently, case mismatches in tag names, forgetting that repo names with slashes need double encoding (my/team/app -> my%252Fteam%252Fapp).","solutions":["Confirm the tag exists: list artifacts with tags (GET .../artifacts?with_tag=true) or query the tag API","Use the digest instead of the tag for stable, race-free lookups","Double-URL-encode repository names that contain '/'","Treat 404 as an expected outcome when the tag may have been removed between listing and fetch"],"exampleFix":"# before: repository name with '/' not encoded -> wrong repo, 404\ncurl https://harbor/api/v2.0/projects/library/repositories/my/team/app/artifacts/latest\n# after: double-URL-encode the repository name\ncurl https://harbor/api/v2.0/projects/library/repositories/my%252Fteam%252Fapp/artifacts/latest","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"art, err := artifactCtl.GetByReference(ctx, repoName, ref, nil)\nif err != nil {\n    if errors.IsErr(err, errors.NotFoundCode) {\n        // tag absent: fall back to digest or treat as deleted\n    }\n    return err\n}","preventionTips":["Prefer digest references for programmatic lookups","Double-URL-encode repository names containing '/'","Handle 404 as expected when tags may be deleted concurrently"],"tags":["go","harbor","api","artifact","tag","not-found","url-encoding"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}