goharbor/harbor · error · github.com/goharbor/harbor/src/lib/errors.Error
PRECONDITION
PRECONDITION
Error message
the tag %s configured as immutable, cannot be updated
What it means
The tag controller's creation path (src/controller/tag/controller.go:103) finds the tag already exists in the repository but is attached to a different artifact. Before re-pointing it, it checks immutability; if a project immutable-tag rule matches, the update is refused with PRECONDITION (HTTP 412).
Source
Thrown at src/controller/tag/controller.go:103
"name": name,
},
}
tags, err := c.List(ctx, query, &Option{
WithImmutableStatus: true,
})
if err != nil {
return 0, err
}
// the tag already exists under the repository
if len(tags) > 0 {
tag := tags[0]
// the tag already exists under the repository and is attached to the artifact, return directly
if tag.ArtifactID == artifactID {
return tag.ID, nil
}
// existing tag must check the immutable status and signature
if tag.Immutable {
return 0, errors.New(nil).WithCode(errors.PreconditionCode).
WithMessagef("the tag %s configured as immutable, cannot be updated", tag.Name)
}
// the tag exists under the repository, but it is attached to other artifact
// update it to point to the provided artifact
tag.ArtifactID = artifactID
tag.PushTime = time.Now()
if err := c.Update(ctx, tag, "ArtifactID", "PushTime"); err != nil {
return 0, err
}
c.touchRepo(ctx, repositoryID)
return tag.ID, nil
}
// the tag doesn't exist under the repository, create it
// use orm.WithTransaction here to avoid the issue:
// https://www.postgresql.org/message-id/002e01c04da9%24a8f95c20%2425efe6c1%40lasting.ro
tagID := int64(0)
if err = orm.WithTransaction(func(ctx context.Context) error {View on GitHub (pinned to 7b2fd08cc5)
Solutions
- Push under a new/unique tag (timestamped or git-sha tags)
- Review and adjust the project's immutable tag rules (Project -> Configuration -> Immutable Tags), e.g. narrow '**' to specific patterns
- If the re-point is intentional and approved, temporarily remove the rule, re-push, re-add the rule
Example fix
# before immutable rule: releases/** docker push myharbor.com/prod/app:releases/v1 # retag -> 412 # after # option 1: unique tag docker push myharbor.com/prod/app:releases/v1-a1b2c3d # option 2: narrow the rule to "releases/**-final" so CI tags stay mutable
Defensive patterns
Strategy: try-catch
Validate before calling
tags, err := tagCtl.List(ctx, &q.Query{Keywords: map[string]any{"RepositoryID": repoID, "Name": name}}, &Option{WithImmutableStatus: true})
if err == nil && len(tags) > 0 && tags[0].Immutable && tags[0].ArtifactID != artifactID {
return fmt.Errorf("tag %s immutable; choose another tag", name)
} Type guard
func isImmutableTagErr(err error) bool {
return errors.IsErr(err, errors.PreconditionCode) &&
strings.Contains(err.Error(), "immutable")
} Try / catch
if _, err := tagCtl.Create(ctx, repoID, artifactID, &model.Tag{Name: name}); err != nil {
if errors.IsErr(err, errors.PreconditionCode) && strings.Contains(err.Error(), "immutable, cannot be updated") {
// push under a unique tag instead of re-pointing the immutable one
}
return err
} Prevention
- Use unique (sha/date) tags for CI pushes; reserve mutable names like 'latest' outside immutable patterns
- Review immutable tag rules before adding new push targets to a pipeline
- Pre-list tags with immutable status when automation must re-point existing names
When it happens
Trigger: Pushing an image that re-points an existing tag (e.g. 'latest') which is protected by a project immutable tag rule; POST /api/v2.0/projects/{p}/repositories/{r}/artifacts/{digest}/tags with a name already bound to another artifact and covered by an immutable rule.
Common situations: CI pipeline pushing a new build to 'stable'/'release' tags that were later made immutable; immutable rule added after the tag existed, blocking subsequent pushes; default 'latest' flows in projects with wildcard immutable rules (e.g. '**').
Related errors
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/4742b21e8bcfcff0.
Report an issue: GitHub.