netbirdio/netbird · warning

invalid filter: %w

Error message

invalid filter: %w

What it means

The capture command validates its positional filter with capture.ParseFilter before sending it to the daemon, and this error wraps the parser's rejection. The accepted grammar is a tcpdump-style subset: host IP, src/dst combined with host/port/net, bare port NUM, net PREFIX/LEN, protocol keywords (tcp, udp, icmp, icmp6, ip, ip6, proto NUM), and the boolean operators and/or/not with parentheses. Anything outside that grammar — unsupported tcpdump keywords, hostnames instead of literal IPs, malformed addresses — is rejected client-side before any RPC.

Source

Thrown at client/cmd/capture.go:113

	} else {
		cmd.PrintErrf("Capturing packets (pcap)... Press Ctrl+C to stop.\n")
	}

	streamErr := streamCapture(ctx, cmd, stream, out)
	cleanupErr := cleanup()
	if streamErr != nil {
		return streamErr
	}
	return cleanupErr
}

func buildCaptureRequest(cmd *cobra.Command, args []string) (*proto.StartCaptureRequest, error) {
	req := &proto.StartCaptureRequest{}

	if len(args) > 0 {
		expr := strings.Join(args, " ")
		if _, err := capture.ParseFilter(expr); err != nil {
			return nil, fmt.Errorf("invalid filter: %w", err)
		}
		req.FilterExpr = expr
	}

	if snap, _ := cmd.Flags().GetUint32("snap-len"); snap > 0 {
		req.SnapLen = snap
	}
	if d, _ := cmd.Flags().GetDuration("duration"); d != 0 {
		if d < 0 {
			return nil, fmt.Errorf("duration must not be negative")
		}
		req.Duration = durationpb.New(d)
	}
	req.Verbose, _ = cmd.Flags().GetBool("verbose")
	req.Ascii, _ = cmd.Flags().GetBool("ascii")

	outPath, _ := cmd.Flags().GetString("output")
	forcePcap, _ := cmd.Flags().GetBool("pcap")

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Re-read the grammar in the error's source file (util/capture/filter.go): rewrite the filter using only host/src/dst/port/net/tcp/udp/icmp/icmp6/ip/ip6/proto with and/or/not
  2. Replace hostnames with literal IP addresses (resolve them yourself first: dig +short myhost)
  3. Fix the specific parse error text — it names the offending token and position for unexpected-token cases
  4. Test simpler sub-expressions incrementally: 'tcp' then 'host 10.0.0.1' then combine with and/or

Example fix

# before: unsupported keywords and a hostname
netbird debug capture portrange 80-90 or host api.example.com

# after: literal IPs and supported keywords
netbird debug capture (port 80 or port 90) or host 203.0.113.10
Defensive patterns

Strategy: validation

Validate before calling

// Validate before starting anything, exactly as the CLI does:
if _, err := capture.ParseFilter(expr); err != nil {
    return fmt.Errorf("invalid filter: %w", err)
}

Prevention

When it happens

Trigger: Using tcpdump keywords the parser does not implement: portrange, less, greater, vlan, arp, ether host, 'port 443 and port 80' with duplicated qualifiers; passing a hostname (host myserver.example.com) where only a literal IP is accepted; an IP typo like 10.0.0 or 10.0.0.256; unbalanced parentheses '(host 10.0.0.1'; trailing tokens the parser did not consume (unexpected token ... at position N).

Common situations: Copy-pasting a working tcpdump expression into netbird debug capture; assuming full BPF support because the syntax looks like tcpdump; shell quoting issues that split the expression (usually fine since args are rejoined with spaces); using net 10.0.0.0/24 vs bare CIDR '10.0.0.0/24' which parses as a term only under net/host context.

Related errors


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