goharbor/harbor · error
empty action
Error message
empty action
What it means
Returned by the retention action index Get when the action string is empty. Retention actions (e.g. retain) are registered at init time into a sync.Map keyed by action name; Get first rejects the empty key before lookup. It signals a malformed retention policy payload where the rule's action field is missing.
Source
Thrown at src/pkg/retention/policy/action/index/index.go:45
func init() {
// Register retain action
Register(action.Retain, action.NewRetainAction)
}
// Register the performer with the corresponding action
func Register(action string, factory action.PerformerFactory) {
if len(action) == 0 || factory == nil {
// do nothing
return
}
index.Store(action, factory)
}
// Get performer with the provided action
func Get(act string, params any, isDryRun bool) (action.Performer, error) {
if len(act) == 0 {
return nil, errors.New("empty action")
}
v, ok := index.Load(act)
if !ok {
return nil, errors.Errorf("action %s is not registered", act)
}
factory, ok := v.(action.PerformerFactory)
if !ok {
return nil, errors.Errorf("invalid action performer registered for action %s", act)
}
return factory(params, isDryRun), nil
}
View on GitHub (pinned to 7b2fd08cc5)
Solutions
- Set the action field on every rule in the retention policy payload (only 'retain' is a valid action in current Harbor)
- Validate the policy JSON before submission, e.g. check rule.action is non-empty for each rule
- If generating policies in code, assert on required fields before calling the retention API
Example fix
// before
rule := map[string]any{"template": "always"}
_, err := action.Get("", params, false)
// after
rule := map[string]any{"action": "retain", "template": "always"}
_, err := action.Get("retain", params, false) Defensive patterns
Strategy: validation
Validate before calling
for _, r := range policy.Rules {
if len(r.Action) == 0 {
return fmt.Errorf("retention rule is missing an action")
}
}
_, err := actionindex.Get(policy.Rules[0].Action, params, dryRun) Prevention
- Validate policy payloads against the retention API schema before submitting
- Use 'retain' as the action; it is the only registered action in current Harbor
- Add integration tests that POST representative policies to catch schema drift
When it happens
Trigger: Submitting a retention policy whose rule JSON omits the action field; programmatically building a policy model with an unset action and passing it to policy evaluation; API POST /retentions with an empty action in the rules array.
Common situations: Hand-crafted policy JSON from scripts or Terraform providers missing the action key; UI/API payload truncated during upgrade; copy-paste of policy templates between Harbor versions with schema changes.
Related errors
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/f39c396f1577deb1.
Report an issue: GitHub.