{"record":{"id":"19a71818b4ea4a2b","repo":"netbirdio/netbird","slug":"a-record-must-be-a-valid-ipv4-address","errorCode":null,"errorMessage":"A record must be a valid IPv4 address","messagePattern":"A record must be a valid IPv4 address","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"management/internals/modules/zones/records/record.go","lineNumber":115,"sourceCode":"\nfunc (r *Record) EventMeta(zoneID, zoneName string) map[string]any {\n\treturn map[string]any{\n\t\t\"name\":      r.Name,\n\t\t\"type\":      string(r.Type),\n\t\t\"content\":   r.Content,\n\t\t\"ttl\":       r.TTL,\n\t\t\"zone_id\":   zoneID,\n\t\t\"zone_name\": zoneName,\n\t}\n}\n\nfunc validateIPv4(content string) error {\n\tif content == \"\" {\n\t\treturn errors.New(\"A record is required\") //nolint:staticcheck\n\t}\n\tip := net.ParseIP(content)\n\tif ip == nil || ip.To4() == nil {\n\t\treturn errors.New(\"A record must be a valid IPv4 address\") //nolint:staticcheck\n\t}\n\treturn nil\n}\n\nfunc validateIPv6(content string) error {\n\tif content == \"\" {\n\t\treturn errors.New(\"AAAA record is required\")\n\t}\n\tip := net.ParseIP(content)\n\tif ip == nil || ip.To4() != nil {\n\t\treturn errors.New(\"AAAA record must be a valid IPv6 address\")\n\t}\n\treturn nil\n}\n","sourceCodeStart":97,"sourceCodeEnd":130,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/management/internals/modules/zones/records/record.go#L97-L130","documentation":"validateIPv4 parses Content with net.ParseIP and requires the result to have a 4-byte form (ip.To4() != nil). It fails for non-IP strings, malformed IPv4 (\"192.0.2.256\", \"192.0.2\"), and IPv6 literals (To4() is nil). Note the corollary: a v4-mapped IPv6 literal like \"::ffff:192.0.2.1\" is accepted because its To4() is non-nil.","triggerScenarios":"Type \"A\" with content \"2001:db8::1\", \"example.com\", \"192.0.2\", or \" 192.0.2.1\" (leading space).","commonSituations":"Pasting a hostname where an address is expected; using the A type for an IPv6 target; address strings copied with whitespace or units from a spreadsheet.","solutions":["Use a dotted-quad IPv4 literal, e.g. \"192.0.2.1\".","If the target is IPv6, change the record type to \"AAAA\" instead.","Trim whitespace and reject hostnames client-side before submission."],"exampleFix":"// before\n{\"name\": \"api\", \"type\": \"A\", \"content\": \"2001:db8::1\"}\n// after\n{\"name\": \"api\", \"type\": \"AAAA\", \"content\": \"2001:db8::1\"}","handlingStrategy":"validation","validationCode":"if api.DNSRecordType(req.Type) == api.DNSRecordTypeA {\n    if ip := net.ParseIP(req.Content); ip == nil || ip.To4() == nil {\n        return fmt.Errorf(\"content %q is not an IPv4 address\", req.Content)\n    }\n}","typeGuard":"func isIPv4Literal(s string) bool {\n    ip := net.ParseIP(strings.TrimSpace(s))\n    return ip != nil && ip.To4() != nil\n}","tryCatchPattern":"if err := rec.Validate(); err != nil {\n    return respondBadRequest(err)\n}","preventionTips":["Parse and validate the address client-side with the same ParseIP/To4 rule.","Trim whitespace from pasted addresses; suggest switching to AAAA when the input parses as IPv6."],"tags":["dns","zones","ipv4","validation"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}