{"record":{"id":"655766588292b758","repo":"netbirdio/netbird","slug":"record-name-is-required","errorCode":null,"errorMessage":"record name is required","messagePattern":"record name is required","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"management/internals/modules/zones/records/record.go","lineNumber":63,"sourceCode":"\treturn &api.DNSRecord{\n\t\tId:      r.ID,\n\t\tName:    r.Name,\n\t\tType:    recordType,\n\t\tContent: r.Content,\n\t\tTtl:     r.TTL,\n\t}\n}\n\nfunc (r *Record) FromAPIRequest(req *api.DNSRecordRequest) {\n\tr.Name = req.Name\n\tr.Type = RecordType(req.Type)\n\tr.Content = req.Content\n\tr.TTL = req.Ttl\n}\n\nfunc (r *Record) Validate() error {\n\tif r.Name == \"\" {\n\t\treturn errors.New(\"record name is required\")\n\t}\n\n\tif !domain.IsValidDomain(r.Name) {\n\t\treturn errors.New(\"invalid record name format\")\n\t}\n\n\tif r.Type == \"\" {\n\t\treturn errors.New(\"record type is required\")\n\t}\n\n\tswitch r.Type {\n\tcase RecordTypeA:\n\t\tif err := validateIPv4(r.Content); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase RecordTypeAAAA:\n\t\tif err := validateIPv6(r.Content); err != nil {\n\t\t\treturn err","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/management/internals/modules/zones/records/record.go#L45-L81","documentation":"Returned by records.Record.Validate() when the Name field is the empty string. A Record is populated from api.DNSRecordRequest via FromAPIRequest, so this surfaces when a DNS record create/update call omits or blanks the name. It is the first check in Validate, so it fires before format, type, and content checks.","triggerScenarios":"POST/PATCH to a zone's records endpoint with body {\"name\":\"\"} or with the name key missing; calling records.NewRecord(accountID, zoneID, \"\", ...) and then Validate(); a test fixture built without setting Name.","commonSituations":"A DNS record form submitted before the name field was filled; a client JSON key typo (e.g. \"label\" instead of \"name\") that decodes to the zero value; programmatic callers that set Content and Type but never Name.","solutions":["Set the record name to a DNS label or FQDN (e.g. \"api\" or \"api.example.com\") in the request body.","If constructing Record in Go, pass a non-empty name to NewRecord (or set r.Name) before calling Validate().","Check the client sends the field the schema names exactly \"name\" (see api.DNSRecordRequest) so it is not silently dropped."],"exampleFix":"// before\n{\"name\": \"\", \"type\": \"A\", \"content\": \"192.0.2.1\", \"ttl\": 300}\n// after\n{\"name\": \"api\", \"type\": \"A\", \"content\": \"192.0.2.1\", \"ttl\": 300}","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(req.Name) == \"\" {\n    return fmt.Errorf(\"record name is required\")\n}","typeGuard":"func hasRecordName(req *api.DNSRecordRequest) bool {\n    return strings.TrimSpace(req.Name) != \"\"\n}","tryCatchPattern":"if err := rec.Validate(); err != nil {\n    return respondBadRequest(err) // map any Validate error to 400 with err.Error()\n}","preventionTips":["Make the name field required in the client form or schema before the request is sent.","Run your own Validate() copy in tests over every fixture you commit.","Log the rejected payload field names at the boundary to catch key-mapping typos early."],"tags":["dns","zones","validation","management-api"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}