slackhq/nebula · error

tun.routes is not an array

Error message

tun.routes is not an array

What it means

The config value at tun.routes is not a JSON/YAML array. parseRoutes receives the decoded config field and first asserts it is []any; if the cast fails the library rejects the configuration because routes can only be expressed as a list of objects.

Source

Thrown at overlay/route.go:80

		if len(gateways) > 0 {
			routing.CalculateBucketsForGateways(gateways)
			routeTree.Insert(r.Cidr, gateways)
		}
	}
	return routeTree, nil
}

func parseRoutes(c *config.C, networks []netip.Prefix) ([]Route, error) {
	var err error

	r := c.Get("tun.routes")
	if r == nil {
		return []Route{}, nil
	}

	rawRoutes, ok := r.([]any)
	if !ok {
		return nil, fmt.Errorf("tun.routes is not an array")
	}

	if len(rawRoutes) < 1 {
		return []Route{}, nil
	}

	routes := make([]Route, len(rawRoutes))
	for i, r := range rawRoutes {
		m, ok := r.(map[string]any)
		if !ok {
			return nil, fmt.Errorf("entry %v in tun.routes is invalid", i+1)
		}

		rMtu, ok := m["mtu"]
		if !ok {
			return nil, fmt.Errorf("entry %v.mtu in tun.routes is not present", i+1)
		}

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Change tun.routes in the config to be a list (array) of route objects
  2. Check YAML indentation so each route entry is a separate list item
  3. Validate the config file with a JSON/YAML schema or linter before startup
  4. If only one route is needed, still wrap it: tun.routes: [{mtu: 1300, route: 10.0.0.0/24}]

Example fix

// before (YAML)
tun:
  routes:
    mtu: 1300
    route: 10.0.0.0/24
// after
tun:
  routes:
    - mtu: 1300
      route: 10.0.0.0/24
Defensive patterns

Strategy: validation

Validate before calling

raw, ok := conf["tun"].(map[string]any)["routes"]
if raw != nil {
    if _, ok := raw.([]any); !ok {
        return fmt.Errorf("tun.routes must be a list of route objects")
    }
}
// run before getAllRoutesFromConfig/loadConfig applies

Type guard

func isRouteArray(v any) bool {
    _, ok := v.([]any)
    return ok
}

Prevention

When it happens

Trigger: Calling getAllRoutesFromConfig (during config load) when the tun.routes field is set to a scalar, string, object/map, or null-typed non-array value (e.g. tun.routes: "10.0.0.0/24" or a single route object instead of a list).

Common situations: Hand-edited config where the user wrote a single route without wrapping it in a list; YAML/JSON indentation mistakes that collapse routes into one map; tooling or templating that emits a string instead of an array.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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