{"record":{"id":"7149f77467c231a5","repo":"netbirdio/netbird","slug":"invalid-record-type-must-be-a-aaaa-or-cname","errorCode":null,"errorMessage":"invalid record type, must be A, AAAA, or CNAME","messagePattern":"invalid record type, must be A, AAAA, or CNAME","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"management/internals/modules/zones/records/record.go","lineNumber":88,"sourceCode":"\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\n\t\t}\n\tcase RecordTypeCNAME:\n\t\tif !domain.IsValidDomainNoWildcard(r.Content) {\n\t\t\treturn errors.New(\"invalid CNAME target format\")\n\t\t}\n\tdefault:\n\t\treturn errors.New(\"invalid record type, must be A, AAAA, or CNAME\")\n\t}\n\n\tif r.TTL < 0 {\n\t\treturn errors.New(\"TTL cannot be negative\")\n\t}\n\n\treturn nil\n}\n\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}","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/management/internals/modules/zones/records/record.go#L70-L106","documentation":"The per-type switch in Validate() has no matching case for the supplied Type and falls to default. Only the exact constants \"A\", \"AAAA\", and \"CNAME\" (records.RecordTypeA/AAAA/CNAME) are accepted; matching is case-sensitive, so \"a\", \"txt\", \"MX\", \"SRV\" all land here.","triggerScenarios":"A record body with \"type\": \"TXT\", \"SRV\", \"MX\", or lowercase \"a\"/\"cname\"; importing a zone export from a provider with record types NetBird zones do not support.","commonSituations":"Migrating DNS data from BIND/Route53 style exports that include TXT/SRV/MX records; a client normalizing types to lowercase; typos like \"AAAA \" with whitespace (no trimming is done).","solutions":["Change the type to exactly \"A\", \"AAAA\", or \"CNAME\" (uppercase, no surrounding whitespace).","Drop or externally host record types this zone model does not support before importing.","Constrain the client's type picker to the three supported values so invalid ones cannot be sent."],"exampleFix":"// before\n{\"name\": \"api\", \"type\": \"txt\", \"content\": \"v=spf1 -all\"}\n// after\n{\"name\": \"api\", \"type\": \"CNAME\", \"content\": \"target.example.com\"}","handlingStrategy":"type-guard","validationCode":"if !isValidRecordType(string(req.Type)) {\n    return fmt.Errorf(\"unsupported record type %q, use A, AAAA, or CNAME\", req.Type)\n}","typeGuard":"func isValidRecordType(t string) bool {\n    switch records.RecordType(t) {\n    case records.RecordTypeA, records.RecordTypeAAAA, records.RecordTypeCNAME:\n        return true\n    }\n    return false\n}","tryCatchPattern":"if err := rec.Validate(); err != nil {\n    return respondBadRequest(err)\n}","preventionTips":["Reject unsupported types at the client with a picker, not free text.","Remember matching is case-sensitive: send uppercase exactly.","When importing zone files, whitelist the three types and report the rest as skipped."],"tags":["dns","zones","validation","record-type"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}