slackhq/nebula · error

nil header

Error message

nil header

What it means

Ad-hoc errors.New("nil header") returned by H.Encode when the header receiver h is nil. It is a nil-receiver guard: encoding a packet header requires a non-nil *H, and calling Encode on a nil header (e.g. a zero-value packet struct) aborts before bytes are written.

Source

Thrown at header/header.go:136

		h.Version, h.TypeName(), h.SubTypeName(), h.Reserved, h.RemoteIndex, h.MessageCounter)
}

// MarshalJSON creates a json string representation of a header
func (h *H) MarshalJSON() ([]byte, error) {
	return json.Marshal(m{
		"version":        h.Version,
		"type":           h.TypeName(),
		"subType":        h.SubTypeName(),
		"reserved":       h.Reserved,
		"remoteIndex":    h.RemoteIndex,
		"messageCounter": h.MessageCounter,
	})
}

// Encode turns header into bytes
func (h *H) Encode(b []byte) ([]byte, error) {
	if h == nil {
		return nil, errors.New("nil header")
	}

	return Encode(b, h.Version, h.Type, h.Subtype, h.RemoteIndex, h.MessageCounter), nil
}

// Parse is a helper function to parses given bytes into new Header struct
func (h *H) Parse(b []byte) error {
	if len(b) < Len {
		return ErrHeaderTooShort
	}
	// get upper 4 bytes
	h.Version = uint8((b[0] >> 4) & 0x0f)
	// get lower 4 bytes
	h.Type = MessageType(b[0] & 0x0f)
	h.Subtype = MessageSubType(b[1])
	h.Reserved = binary.BigEndian.Uint16(b[2:4])
	h.RemoteIndex = binary.BigEndian.Uint32(b[4:8])
	h.MessageCounter = binary.BigEndian.Uint64(b[8:16])

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Initialize the header before encoding — ensure the code path always constructs a valid *H
  2. Check the error from any earlier Parse/build step that produced the header; do not pass a nil result onward
  3. Add a nil check in the caller before invoking Encode

Example fix

// before
var h *header.H
b, err := h.Encode(buf) // "nil header"
// after
h := &header.H{Version: header.Version, Type: header.Message, Subtype: 0}
b, err := h.Encode(buf)
Defensive patterns

Strategy: validation

Validate before calling

if h == nil {
    return fmt.Errorf("cannot encode nil header")
}

Type guard

func headerReady(h *header.H) bool {
    return h != nil
}

Try / catch

b, err := h.Encode(buf)
if err != nil {
    return fmt.Errorf("header encode: %w", err)
}

Prevention

When it happens

Trigger: Calling Encode on a nil *H — e.g. a header variable that was never populated, or a function returning (*H, error) whose nil result is passed straight to Encode (as in the TestCloseTunnelAuthenticated call path).

Common situations: A build/parse step earlier failed silently and left the header nil; logic error where the header struct was conditionally created; test harness forgetting to initialize the header.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/7c5977adef51653c. Report an issue: GitHub.