txthinking/brook · error

Invalid prefer

Error message

Invalid prefer

What it means

NewDialWithDNS validates the prefer parameter, which selects whether A (IPv4) or AAAA (IPv6) DNS records are queried. Any value other than the exact strings "A" or "AAAA" is rejected with "Invalid prefer" before a client is constructed.

Source

Thrown at plugins/dialwithdns/dialwithdns.go:35

import (
	"errors"
	"net"
	"strconv"
	"strings"

	"github.com/txthinking/brook"
	"github.com/txthinking/socks5"
)

type DialWithDNS struct {
	DNSClient *brook.DNSClient
	DOHClient *brook.DOHClient
	Prefer    string
}

func NewDialWithDNS(dns, prefer string) (*DialWithDNS, error) {
	if prefer != "A" && prefer != "AAAA" {
		return nil, errors.New("Invalid prefer")
	}
	if !strings.HasPrefix(dns, "https://") {
		return &DialWithDNS{DNSClient: &brook.DNSClient{Server: dns}, Prefer: prefer}, nil
	}
	dc, err := brook.NewDOHClient(dns)
	if err != nil {
		return nil, err
	}
	return &DialWithDNS{DOHClient: dc, Prefer: prefer}, nil
}

func (p *DialWithDNS) IP(domain string) (net.IP, error) {
	if p.Prefer == "A" {
		if p.DNSClient != nil {
			ip, err := p.DNSClient.A(domain)
			if err != nil {
				return nil, err
			}

View on GitHub (pinned to 5cd13ef3b1)

Solutions

  1. Pass exactly "A" for IPv4 preference or "AAAA" for IPv6 preference.
  2. Normalize/validate the config value before calling: uppercase it and map synonyms ("ipv4"->"A", "ipv6"->"AAAA").
  3. Guard against empty values by defaulting to "A" when the config field is unset.

Example fix

// before
p, err := NewDialWithDNS(dns, "ipv4")
// after
prefer := "A"
if strings.EqualFold(cfg.Prefer, "AAAA") || strings.EqualFold(cfg.Prefer, "ipv6") {
    prefer = "AAAA"
}
p, err := NewDialWithDNS(dns, prefer)
Defensive patterns

Strategy: validation

Validate before calling

func validPrefer(p string) bool { return p == "A" || p == "AAAA" }
if !validPrefer(cfg.Prefer) { return fmt.Errorf("prefer must be \"A\" or \"AAAA\", got %q", cfg.Prefer) }

Try / catch

p, err := NewDialWithDNS(dns, prefer)
if err != nil && strings.Contains(err.Error(), "Invalid prefer") {
    prefer = "A" // safe default
    p, err = NewDialWithDNS(dns, prefer)
}

Prevention

When it happens

Trigger: Calling NewDialWithDNS(dns, prefer) with prefer values like "a", "ipv4", "A/AAAA", "", or any other non-exact string; wiring the plugin with a mistyped config flag.

Common situations: Case-sensitivity mistakes ("a" instead of "A"); passing descriptive labels like "ipv6"; empty prefer read from an unset config value.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of txthinking/brook@5cd13ef3b1 (2026-09-06). Data as JSON: /api/errors/e6e221cbc9fa7686. Report an issue: GitHub.