netbirdio/netbird · error
build packet: %w
Error message
build packet: %w
What it means
TracePacketFromBuilder wraps any failure from PacketBuilder.Build, which itself aggregates the earlier builder errors: mixed address families in buildIPLayer, checksum network-layer mismatch in the TCP/UDP builders, or SerializeLayers failures (length overflow, unencodable layer state). This is the single error surface a caller of the trace API sees, so the underlying cause is only visible in the wrapped chain.
Source
Thrown at client/firewall/uspfilter/tracer.go:264
switch protocol {
case fw.ProtocolTCP:
return layers.IPProtocolTCP
case fw.ProtocolUDP:
return layers.IPProtocolUDP
case fw.ProtocolICMP:
if isV6 {
return layers.IPProtocolICMPv6
}
return layers.IPProtocolICMPv4
default:
return 0
}
}
func (m *Manager) TracePacketFromBuilder(builder *PacketBuilder) (*PacketTrace, error) {
packetData, err := builder.Build()
if err != nil {
return nil, fmt.Errorf("build packet: %w", err)
}
return m.TracePacket(packetData, builder.Direction), nil
}
func (m *Manager) TracePacket(packetData []byte, direction fw.RuleDirection) *PacketTrace {
d := m.decoders.Get().(*decoder)
defer m.decoders.Put(d)
trace := &PacketTrace{Direction: direction}
// Initial packet decoding
if err := d.decodePacket(packetData); err != nil {
trace.AddResult(StageReceived, fmt.Sprintf("Failed to decode packet: %v", err), false)
return trace
}
View on GitHub (pinned to 93e97f4bf1)
Solutions
- Inspect errors.Is/errors.Unwrap on the returned error to find which builder stage failed (family, checksum, or serialize)
- Validate before calling: both IPs valid and same-family, ports set, PayloadSize bounded
- Normalize addresses with Unmap() at ingestion so v4-mapped v6 does not sneak into the family check
- Add per-protocol happy-path tests so regressions surface as specific builder errors, not this generic wrap
Example fix
// before
trace, err := m.TracePacketFromBuilder(b)
// after
if err := b.Validate(); err != nil { // same-family + bounds checks
return nil, err
}
trace, err := m.TracePacketFromBuilder(b)
if err != nil {
return nil, fmt.Errorf("trace packet: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
if !p.SrcIP.IsValid() || !p.DstIP.IsValid() || p.SrcIP.Is4() != p.DstIP.Is4() {
return errors.New("packet builder inputs invalid")
}
if p.PayloadSize > 0xffff-28 {
return errors.New("payload too large")
}
trace, err := m.TracePacketFromBuilder(p) Type guard
func traceInputsValid(p *PacketBuilder) bool {
return p.SrcIP.IsValid() && p.DstIP.IsValid() &&
p.SrcIP.Is4() == p.DstIP.Is4() && sanePayloadSize(p.PayloadSize)
} Try / catch
trace, err := m.TracePacketFromBuilder(b)
if err != nil {
// unwrap to classify: family / checksum / serialize, then fix inputs and rebuild
log.Debugf("trace build failed: %v", err)
return nil, err
} Prevention
- Validate builder inputs at your tool's entry point, closest to the user input
- Unwrap the error chain before deciding retry vs fail: only input errors are deterministic
- Keep one code path that constructs PacketBuilder so validation lives in one place
When it happens
Trigger: Calling TracePacketFromBuilder with a PacketBuilder whose SrcIP/DstIP families differ or one is unset; PayloadSize beyond the 16-bit length limits; an ICMPv6 trace where the network-layer assertion failed; any refactor that breaks the ipLayer/transportLayer pairing.
Common situations: Building trace/diagnostics tooling on uspfilter and constructing PacketBuilder values from user or config input without prior normalization; automated tests sweeping address families and payload sizes and hitting an unhandled combination.
Related errors
- mixed address families: src=%s dst=%s
- set network layer for TCP checksum: %w
- set network layer for UDP checksum: %w
- serialize packet: %w
- daemon up failed: %v
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/83f29fc1ee7e382f.
Report an issue: GitHub.