slackhq/nebula · error
only one of group or groups should be defined, both provided
Error message
only one of group or groups should be defined, both provided
What it means
In firewall rule normalization, the config allows either the singular 'group' or plural 'groups' field. Providing both is ambiguous, so the rule is rejected with this error rather than merging them. This lives in the rule-translation step that converts YAML firewall rule structs into internal rules.
Source
Thrown at firewall.go:1004
switch reflect.TypeOf(rg).Kind() {
case reflect.Slice:
v := reflect.ValueOf(rg)
r.Groups = make([]string, v.Len())
for i := 0; i < v.Len(); i++ {
r.Groups[i] = v.Index(i).Interface().(string)
}
case reflect.String:
r.Groups = []string{rg.(string)}
default:
r.Groups = []string{fmt.Sprintf("%v", rg)}
}
}
//flatten group vs groups
if singleGroup != "" {
// Check if we have both groups and group provided in the rule config
if len(r.Groups) > 0 {
return r, fmt.Errorf("only one of group or groups should be defined, both provided")
}
r.Groups = []string{singleGroup}
}
return r, nil
}
// sanity returns an error if the rule would be evaluated in a way that would short-circuit a configured check on a wildcard value
// rules are evaluated as "port AND proto AND (ca_sha OR ca_name) AND (host OR group OR groups OR cidr) AND local_cidr"
func (r *rule) sanity() error {
//port, proto, local_cidr are AND, no need to check here
//ca_sha and ca_name don't have a wildcard value, no need to check here
groupsEmpty := len(r.Groups) == 0
hostEmpty := r.Host == ""
cidrEmpty := r.Cidr == ""
if (groupsEmpty && hostEmpty && cidrEmpty) == true {
return nil //no content!View on GitHub (pinned to dd8f660c0a)
Solutions
- Keep only the 'groups' list and move the singular value into it
- Or keep only 'group' if a single group suffices
- Search your config for rules containing both keys
Example fix
// before group: prod groups: - prod - staging // after groups: - prod - staging
Defensive patterns
Strategy: validation
Validate before calling
func checkGroupConflict(r FirewallRuleConfig) error {
if r.Group != "" && len(r.Groups) > 0 {
return fmt.Errorf("rule defines both group and groups")
}
return nil
} Type guard
func hasGroupConflict(group string, groups []string) bool {
return group != "" && len(groups) > 0
} Try / catch
if err := loadFirewallConfig(cfg); err != nil {
if strings.Contains(err.Error(), "only one of group or groups") {
return fmt.Errorf("fix rule config: %w", err)
}
return err
} Prevention
- Standardize on 'groups' lists in all configs
- Grep configs for rules containing both group and groups keys
- When merging config fragments, normalize singular group into groups first
When it happens
Trigger: A single firewall rule in the YAML/config struct defines both 'group: foo' and 'groups: [foo, bar]'.
Common situations: Merged config files where one fragment used group and another used groups; copy-paste from examples mixing syntax; templating that appends a singular group to a rule already carrying a list.
Related errors
- Empty configuration
- group should contain a single value, an array with more than
- config `%s` has invalid value (type %T): %v
- %s rule #%v; `%s`
- start port was lower than end port
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/443add904fe40221.
Report an issue: GitHub.