slackhq/nebula · error

encoded Details was nil

Error message

encoded Details was nil

What it means

After protobuf unmarshaling, the RawNebulaCertificate must contain a Details message; a nil Details means the serialized certificate lacks the required details payload (name, networks, ips, etc.), which is invalid for a v1 nebula certificate.

Source

Thrown at cert/cert_v1.go:413

	}
	c.signature = b
	return nil
}

// unmarshalCertificateV1 will unmarshal a protobuf byte representation of a nebula cert
// if the publicKey is provided here then it is not required to be present in `b`
func unmarshalCertificateV1(b []byte, publicKey []byte) (*certificateV1, error) {
	if len(b) == 0 {
		return nil, fmt.Errorf("nil byte array")
	}
	var rc RawNebulaCertificate
	err := proto.Unmarshal(b, &rc)
	if err != nil {
		return nil, err
	}

	if rc.Details == nil {
		return nil, fmt.Errorf("encoded Details was nil")
	}

	if len(rc.Details.Ips)%2 != 0 {
		return nil, fmt.Errorf("encoded IPs should be in pairs, an odd number was found")
	}

	if len(rc.Details.Subnets)%2 != 0 {
		return nil, fmt.Errorf("encoded Subnets should be in pairs, an odd number was found")
	}

	nc := certificateV1{
		details: detailsV1{
			name:           rc.Details.Name,
			groups:         make([]string, len(rc.Details.Groups)),
			networks:       make([]netip.Prefix, len(rc.Details.Ips)/2),
			unsafeNetworks: make([]netip.Prefix, len(rc.Details.Subnets)/2),
			notBefore:      time.Unix(rc.Details.NotBefore, 0),
			notAfter:       time.Unix(rc.Details.NotAfter, 0),

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Ensure the certificate is marshaled with Details populated (marshal via the library's Marshal, not by hand)
  2. Validate the certificate source; re-read or re-issue the certificate
  3. Check for corruption in transport/storage of the certificate bytes
  4. Inspect the raw protobuf (e.g. protoc --decode) to confirm Details is present

Example fix

// before
bad := &cert.RawNebulaCertificate{Version: 1}
b, _ := proto.Marshal(bad) // Details nil
unmarshalCertificateV1(b, nil)
// after
good, _ := someCert.Marshal() // includes Details
unmarshalCertificateV1(good, nil)
Defensive patterns

Strategy: try-catch

Try / catch

c, err := unmarshalCertificateV1(b, nil)
if err != nil {
    if strings.Contains(err.Error(), "encoded Details was nil") {
        return nil, fmt.Errorf("certificate bytes are malformed (missing Details); re-issue or re-read the cert")
    }
    return nil, err
}

Prevention

When it happens

Trigger: unmarshalCertificateV1 receives bytes that decode to a RawNebulaCertificate with rc.Details == nil — e.g. an empty or hand-crafted protobuf message, or data corrupted so the Details submessage was dropped.

Common situations: Manually constructing or mutating RawNebulaCertificate without populating Details; truncation/corruption in transit; writing a certificate with only the version field set; test fixtures with minimal protobufs.

Related errors


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