slackhq/nebula · error

invalid mask (type %T): %v

Error message

invalid mask (type %T): %v

What it means

The `mask` value in a calculated_remotes entry must be a string parseable as a CIDR prefix. This error fires when the mask key exists but its value is not a string (e.g. a number, list, or map), printing the offending Go type via %T.

Source

Thrown at calculated_remote.go:138

		l = append(l, c)
	}

	return l, nil
}

func newCalculatedRemotesEntryFromConfig(cidr netip.Prefix, raw any) (*calculatedRemote, error) {
	rawMap, ok := raw.(map[string]any)
	if !ok {
		return nil, fmt.Errorf("invalid type: %T", raw)
	}

	rawValue := rawMap["mask"]
	if rawValue == nil {
		return nil, fmt.Errorf("missing mask: %v", rawMap)
	}
	rawMask, ok := rawValue.(string)
	if !ok {
		return nil, fmt.Errorf("invalid mask (type %T): %v", rawValue, rawValue)
	}
	maskCidr, err := netip.ParsePrefix(rawMask)
	if err != nil {
		return nil, fmt.Errorf("invalid mask: %s", rawMask)
	}

	var port int
	rawValue = rawMap["port"]
	if rawValue == nil {
		return nil, fmt.Errorf("missing port: %v", rawMap)
	}
	switch v := rawValue.(type) {
	case int:
		port = v
	case string:
		port, err = strconv.Atoi(v)
		if err != nil {
			return nil, fmt.Errorf("invalid port: %s: %w", v, err)

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Set mask to a plain CIDR string, quoting it if YAML mangles it (e.g. mask: "10.0.0.0/8")
  2. Inspect the %T in the message to see what YAML parsed the value as (e.g. []interface {})
  3. Remove any brackets/extra structure so the mask is a single scalar string

Example fix

// before
- mask:
    - 10.0.0.0/8
  port: 4242
// after
- mask: 10.0.0.0/8
  port: 4242
Defensive patterns

Strategy: type-guard

Validate before calling

if v, ok := m["mask"]; ok {
	s, isStr := v.(string)
	if !isStr {
		return fmt.Errorf("mask must be a CIDR string, got %T", v)
	}
	if _, err := netip.ParsePrefix(s); err != nil {
		return fmt.Errorf("mask %q is not a valid CIDR", s)
	}
}

Type guard

func isStringCIDR(v any) bool {
	s, ok := v.(string)
	if !ok {
		return false
	}
	_, err := netip.ParsePrefix(s)
	return err == nil
}

Try / catch

if err != nil {
	if strings.Contains(err.Error(), "invalid mask (type") {
		return fmt.Errorf("mask must be a plain CIDR string: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: A calculated_remotes entry with a mask value like `- mask: [10.0.0.0/8]` (list), an unquoted value YAML coerces to a non-string type, or a nested map under `mask`.

Common situations: YAML coercing values into sequences, copy-paste artifacts like brackets or quotes inside the value, or generated configs emitting masks as arrays.

Related errors


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