slackhq/nebula · error

config `%s` has invalid type: %T

Error message

config `%s` has invalid type: %T

What it means

NewCalculatedRemotesFromConfig reads the `lighthouse.calculated_remotes` key and asserts the raw value is a map[string]any (a TOML/YAML table keyed by CIDR). If the configured value is any other type (string, list, bool, number), the library cannot enumerate CIDR keys and throws this error including the offending Go type.

Source

Thrown at calculated_remote.go:89

	maskb = binary.BigEndian.Uint64(mask[8:])
	maskAddrb = binary.BigEndian.Uint64(maskAddr[8:])
	calcAddrb = binary.BigEndian.Uint64(calcAddr[8:])
	ap.Lo = (maskAddrb & maskb) | (calcAddrb & ^maskb)

	return &ap
}

func NewCalculatedRemotesFromConfig(c *config.C, k string) (*bart.Table[[]*calculatedRemote], error) {
	value := c.Get(k)
	if value == nil {
		return nil, nil
	}

	calculatedRemotes := new(bart.Table[[]*calculatedRemote])

	rawMap, ok := value.(map[string]any)
	if !ok {
		return nil, fmt.Errorf("config `%s` has invalid type: %T", k, value)
	}
	for rawCIDR, rawValue := range rawMap {
		cidr, err := netip.ParsePrefix(rawCIDR)
		if err != nil {
			return nil, fmt.Errorf("config `%s` has invalid CIDR: %s", k, rawCIDR)
		}

		entry, err := newCalculatedRemotesListFromConfig(cidr, rawValue)
		if err != nil {
			return nil, fmt.Errorf("config '%s.%s': %w", k, rawCIDR, err)
		}

		calculatedRemotes.Insert(cidr, entry)
	}

	return calculatedRemotes, nil
}

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Rewrite the calculated_remotes value as a mapping from CIDR strings to entry lists
  2. Check the %T in the error message to see what type was actually parsed (e.g. string vs map)
  3. Fix file indentation so nested entries parse as a table, not a continuation of the parent key

Example fix

// before
lighthouse:
  calculated_remotes: 10.0.42.0/24
// after
lighthouse:
  calculated_remotes:
    10.0.42.0/24:
      - mask: 10.0.0.0/8
        port: 4242
Defensive patterns

Strategy: validation

Validate before calling

value := c.Get("lighthouse")
if value != nil {
	if _, ok := value.(map[string]any); !ok {
		return fmt.Errorf("lighthouse.calculated_remotes must be a table, got %T", value)
	}
}

Type guard

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

Try / catch

tbl, err := NewCalculatedRemotesFromConfig(c, "lighthouse.calculated_remotes")
if err != nil {
	if strings.Contains(err.Error(), "has invalid type") {
		return fmt.Errorf("check calculated_remotes structure in config: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling NewCalculatedRemotesFromConfig (via reload) when the configured `calculated_remotes` value is not a table/map — e.g. a bare string, an array, or a scalar in the nebula config file.

Common situations: YAML/TOML indentation mistakes that collapse the calculated_remotes block into a scalar, or users writing calculated_remotes as a list instead of a map of CIDRs.

Related errors


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