slackhq/nebula · error

%s rule #%v; local_cidr did not parse; %s

Error message

%s rule #%v; local_cidr did not parse; %s

What it means

Identical to the cidr check, AddFirewallRulesFromConfig validates each rule's local_cidr with netip.ParsePrefix unless it is empty or "any". local_cidr constrains the destination address inside the tunnel, so it must be a valid IP prefix.

Source

Thrown at firewall.go:397

			}
		default:
			return fmt.Errorf("%s rule #%v; proto was not understood; `%s`", table, i, r.Proto)
		}
		if err != nil {
			return fmt.Errorf("%s rule #%v; %s %s", table, i, errPort, err)
		}

		if r.Cidr != "" && r.Cidr != "any" {
			_, err = netip.ParsePrefix(r.Cidr)
			if err != nil {
				return fmt.Errorf("%s rule #%v; cidr did not parse; %s", table, i, err)
			}
		}

		if r.LocalCidr != "" && r.LocalCidr != "any" {
			_, err = netip.ParsePrefix(r.LocalCidr)
			if err != nil {
				return fmt.Errorf("%s rule #%v; local_cidr did not parse; %s", table, i, err)
			}
		}

		if warning := r.sanity(); warning != nil {
			l.Warn("firewall rule sanity check",
				"table", table,
				"rule", i,
				"warning", warning,
			)
		}

		err = fw.AddRule(inbound, proto, startPort, endPort, r.Groups, r.Host, r.Cidr, r.LocalCidr, r.CAName, r.CASha)
		if err != nil {
			return fmt.Errorf("%s rule #%v; `%s`", table, i, err)
		}
	}

	return nil

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Provide a valid CIDR prefix for local_cidr (e.g. "192.168.1.0/24").
  2. Use "any" if the rule should match any local destination.
  3. Confirm the value is a prefix (IP + /mask), not a bare IP or hostname.

Example fix

// before (config)
- local_cidr: 192.168.1.0
  port: 22
  proto: tcp
  group: admins
// after
- local_cidr: 192.168.1.0/24
  port: 22
  proto: tcp
  group: admins
Defensive patterns

Strategy: validation

Validate before calling

import "netip"

func validateLocalCidr(rules []map[string]any) error {
    for i, r := range rules {
        v, _ := r["local_cidr"].(string)
        if v == "" || v == "any" { continue }
        if _, err := netip.ParsePrefix(v); err != nil {
            return fmt.Errorf("rule #%d: local_cidr %q invalid: %v", i, v, err)
        }
    }
    return nil
}

Try / catch

if err := fw.AddFirewallRulesFromConfig(l, "inbound", rules); err != nil {
    if strings.Contains(err.Error(), "local_cidr did not parse") {
        log.Fatalf("local_cidr must be a CIDR prefix or 'any': %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: A rule with local_cidr like "192.168.1.0" (missing /prefix), "0.0.0.0/0/0", or other malformed prefix strings, and not "any".

Common situations: Copy-paste errors when configuring unsafe_routes/routed ranges, forgetting the prefix length, or confusing local_cidr with the host.cidr format.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/25e9377e6ccd0c8b. Report an issue: GitHub.