netbirdio/netbird · error

invalid domain name

Error message

invalid domain name

What it means

errInvalidDomainName is a sentinel in nameserver.go, returned wrapped ("invalid domain name: <detail>") by validateDomain when nbdomain.ValidateDomains rejects a nameserver match domain. validateDomain first trims one trailing dot (FQDN form is allowed) and has already rejected "*." wildcards, so this error comes from the domain itself: empty or over-long labels (>63 chars), total length limits, empty labels ("a..b"), or a FromString/idna conversion failure.

Source

Thrown at management/server/nameserver.go:24

	"fmt"
	"slices"
	"strings"
	"unicode/utf8"

	"github.com/rs/xid"

	nbdns "github.com/netbirdio/netbird/dns"
	"github.com/netbirdio/netbird/management/server/activity"
	"github.com/netbirdio/netbird/management/server/affectedpeers"
	"github.com/netbirdio/netbird/management/server/permissions/modules"
	"github.com/netbirdio/netbird/management/server/permissions/operations"
	"github.com/netbirdio/netbird/management/server/store"
	"github.com/netbirdio/netbird/management/server/types"
	nbdomain "github.com/netbirdio/netbird/shared/management/domain"
	"github.com/netbirdio/netbird/shared/management/status"
)

var errInvalidDomainName = errors.New("invalid domain name")

// GetNameServerGroup gets a nameserver group object from account and nameserver group IDs
func (am *DefaultAccountManager) GetNameServerGroup(ctx context.Context, accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) {
	allowed, ctx, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Nameservers, operations.Read)
	if err != nil {
		return nil, status.NewPermissionValidationError(err)
	}
	if !allowed {
		return nil, status.NewPermissionDeniedError()
	}

	return am.Store.GetNameServerGroupByID(ctx, store.LockingStrengthNone, accountID, nsGroupID)
}

// CreateNameServerGroup creates and saves a new nameserver group
func (am *DefaultAccountManager) CreateNameServerGroup(ctx context.Context, accountID string, name, description string, nameServerList []nbdns.NameServer, groups []string, primary bool, domains []string, enabled bool, userID string, searchDomainEnabled bool) (*nbdns.NameServerGroup, error) {
	allowed, ctx, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Nameservers, operations.Create)
	if err != nil {

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Fix the domain string: single dots between labels, no spaces, each label 1-63 chars.
  2. Punycode-convert unicode domains before sending; a trailing dot is fine here (it is trimmed).
  3. Because the sentinel is wrapped with %w, inspect with errors.Is(err, errInvalidDomainName) when you need programmatic handling.

Example fix

// before
nsGroup.Domains = []string{"exa mple.com"}
// after
nsGroup.Domains = []string{"example.com"}
Defensive patterns

Strategy: validation

Validate before calling

for _, d := range nsGroup.Domains {
    trimmed := strings.TrimSuffix(d, ".")
    if _, err := nbdomain.ValidateDomains([]string{trimmed}); err != nil {
        return fmt.Errorf("match domain %q invalid: %v", d, err)
    }
}

Try / catch

if err := am.SaveNameServerGroup(ctx, accountID, userID, nsGroup); err != nil {
    if errors.Is(err, errInvalidDomainName) {
        // point the user at the domains field; err text names the offending domain
    }
    return err
}

Prevention

When it happens

Trigger: CreateNameServerGroup/UpdateNameServerGroup (or the equivalent HTTP/gRPC handlers) with a domains entry like "exa mple.com", "example..com", a label over 63 chars, or an empty string after trimming the dot.

Common situations: Copy-pasted domains containing a space or an empty label; a match domain built by string concatenation that produced ".."; assuming nameserver match domains accept the same syntax as ACL/domain resources.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/e9af8658e7a5b855. Report an issue: GitHub.