slackhq/nebula · error
%s rule #%v; at least one of host, group, cidr, local_cidr,
Error message
%s rule #%v; at least one of host, group, cidr, local_cidr, ca_name, or ca_sha must be provided
What it means
Every firewall rule must select some target: a host, at least one group, a cidr, a local_cidr, a ca_name, or a ca_sha. AddFirewallRulesFromConfig rejects rules that specify none of these, because such a rule could never match a meaningful connection set.
Source
Thrown at firewall.go:349
}
rs, ok := r.([]any)
if !ok {
return fmt.Errorf("%s failed to parse, should be an array of rules", table)
}
for i, t := range rs {
r, err := convertRule(l, t, table, i)
if err != nil {
return fmt.Errorf("%s rule #%v; %s", table, i, err)
}
if r.Code != "" && r.Port != "" {
return fmt.Errorf("%s rule #%v; only one of port or code should be provided", table, i)
}
if r.Host == "" && len(r.Groups) == 0 && r.Cidr == "" && r.LocalCidr == "" && r.CAName == "" && r.CASha == "" {
return fmt.Errorf("%s rule #%v; at least one of host, group, cidr, local_cidr, ca_name, or ca_sha must be provided", table, i)
}
var sPort, errPort string
if r.Code != "" {
errPort = "code"
sPort = r.Code
} else {
errPort = "port"
sPort = r.Port
}
var proto uint8
var startPort, endPort int32
switch r.Proto {
case "any":
proto = firewall.ProtoAny
startPort, endPort, err = parsePort(sPort)
case "tcp":View on GitHub (pinned to dd8f660c0a)
Solutions
- Add a selector to the rule — typically "group: <name>" or "cidr: <prefix>".
- For host-specific rules use "host", for CA-based trust use "ca_name" or "ca_sha".
- Use "cidr: 0.0.0.0/0" (and/or "local_cidr: any") only if you truly intend an allow-all rule.
Example fix
// before (config) - port: 443 proto: tcp // after - port: 443 proto: tcp group: web-servers
Defensive patterns
Strategy: validation
Validate before calling
func ruleHasSelector(rule map[string]any) bool {
for _, k := range []string{"host", "group", "groups", "cidr", "local_cidr", "ca_name", "ca_sha"} {
if v, ok := rule[k]; ok && v != nil && v != "" {
return true
}
}
return false
}
// before AddFirewallRulesFromConfig: ensure ruleHasSelector(r) for every rule Try / catch
if err := fw.AddFirewallRulesFromConfig(l, "outbound", rules); err != nil {
if strings.Contains(err.Error(), "at least one of host, group") {
log.Fatalf("every rule needs host/group/cidr/local_cidr/ca_name/ca_sha: %v", err)
}
return err
} Prevention
- Require a selector field in your rule template/snippet library.
- Never strip selector fields when simplifying example configs.
- Add a CI check that every firewall rule has at least one selector key.
When it happens
Trigger: A rule with only port/proto (e.g. {port: "443", proto: "tcp"}) and no host, group, cidr, local_cidr, ca_name, or ca_sha field.
Common situations: Oversimplified example configs, deleting the group/cidr line while editing, or templating that leaves selector fields empty.
Related errors
- unknown protocol %v
- %s failed to parse, should be an array of rules
- %s rule #%v; only one of port or code should be provided
- %s rule #%v; proto was not understood; `%s`
- ErrInvalidLocalIP
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/60f35e228c988457.
Report an issue: GitHub.