{"record":{"id":"364ce7433da63874","repo":"slackhq/nebula","slug":"invalid-mask-type-t-v","errorCode":null,"errorMessage":"invalid mask (type %T): %v","messagePattern":"invalid mask \\(type %T\\): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"calculated_remote.go","lineNumber":138,"sourceCode":"\t\tl = append(l, c)\n\t}\n\n\treturn l, nil\n}\n\nfunc newCalculatedRemotesEntryFromConfig(cidr netip.Prefix, raw any) (*calculatedRemote, error) {\n\trawMap, ok := raw.(map[string]any)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid type: %T\", raw)\n\t}\n\n\trawValue := rawMap[\"mask\"]\n\tif rawValue == nil {\n\t\treturn nil, fmt.Errorf(\"missing mask: %v\", rawMap)\n\t}\n\trawMask, ok := rawValue.(string)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid mask (type %T): %v\", rawValue, rawValue)\n\t}\n\tmaskCidr, err := netip.ParsePrefix(rawMask)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid mask: %s\", rawMask)\n\t}\n\n\tvar port int\n\trawValue = rawMap[\"port\"]\n\tif rawValue == nil {\n\t\treturn nil, fmt.Errorf(\"missing port: %v\", rawMap)\n\t}\n\tswitch v := rawValue.(type) {\n\tcase int:\n\t\tport = v\n\tcase string:\n\t\tport, err = strconv.Atoi(v)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid port: %s: %w\", v, err)","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/calculated_remote.go#L120-L156","documentation":"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.","triggerScenarios":"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`.","commonSituations":"YAML coercing values into sequences, copy-paste artifacts like brackets or quotes inside the value, or generated configs emitting masks as arrays.","solutions":["Set mask to a plain CIDR string, quoting it if YAML mangles it (e.g. mask: \"10.0.0.0/8\")","Inspect the %T in the message to see what YAML parsed the value as (e.g. []interface {})","Remove any brackets/extra structure so the mask is a single scalar string"],"exampleFix":"// before\n- mask:\n    - 10.0.0.0/8\n  port: 4242\n// after\n- mask: 10.0.0.0/8\n  port: 4242","handlingStrategy":"type-guard","validationCode":"if v, ok := m[\"mask\"]; ok {\n\ts, isStr := v.(string)\n\tif !isStr {\n\t\treturn fmt.Errorf(\"mask must be a CIDR string, got %T\", v)\n\t}\n\tif _, err := netip.ParsePrefix(s); err != nil {\n\t\treturn fmt.Errorf(\"mask %q is not a valid CIDR\", s)\n\t}\n}","typeGuard":"func isStringCIDR(v any) bool {\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn false\n\t}\n\t_, err := netip.ParsePrefix(s)\n\treturn err == nil\n}","tryCatchPattern":"if err != nil {\n\tif strings.Contains(err.Error(), \"invalid mask (type\") {\n\t\treturn fmt.Errorf(\"mask must be a plain CIDR string: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Quote mask values in YAML to prevent type coercion (mask: \"10.0.0.0/8\")","Avoid sequences or nested maps as mask values — a single string only","Verify parsed types by dumping the config section before reload"],"tags":["nebula","config","type-error","yaml","calculated-remotes"],"backgroundTag":"config-type-mismatch","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}