slackhq/nebula · error

encoded EncryptionMetadata was nil

Error message

encoded EncryptionMetadata was nil

What it means

After protobuf unmarshalling, RawNebulaEncryptedData.EncryptionMetadata must be present - it carries the Argon2 parameters and nonce needed for decryption. A decoded message with EncryptionMetadata nil means the serialized blob lacked the metadata sub-message, so decryption cannot proceed.

Source

Thrown at cert/crypto.go:206

	default:
		return nil, fmt.Errorf("invalid curve: %v", curve)
	}
}

// UnmarshalNebulaEncryptedData will unmarshal a protobuf byte representation of a nebula cert into its
// protobuf-generated struct.
func UnmarshalNebulaEncryptedData(b []byte) (*NebulaEncryptedData, error) {
	if len(b) == 0 {
		return nil, fmt.Errorf("nil byte array")
	}
	var rned RawNebulaEncryptedData
	err := proto.Unmarshal(b, &rned)
	if err != nil {
		return nil, err
	}

	if rned.EncryptionMetadata == nil {
		return nil, fmt.Errorf("encoded EncryptionMetadata was nil")
	}

	if rned.EncryptionMetadata.Argon2Parameters == nil {
		return nil, fmt.Errorf("encoded Argon2Parameters was nil")
	}

	params, err := unmarshalArgon2Parameters(rned.EncryptionMetadata.Argon2Parameters)
	if err != nil {
		return nil, err
	}

	ned := NebulaEncryptedData{
		EncryptionMetadata: NebulaEncryptionMetadata{
			EncryptionAlgorithm: rned.EncryptionMetadata.EncryptionAlgorithm,
			Argon2Parameters:    *params,
		},
		Ciphertext: rned.Ciphertext,
	}

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Ensure the encryption side populated EncryptionMetadata (via EncryptionMetadata in NebulaEncryptedData) before marshalling; re-encrypt the data with the standard EncryptAndMarshal* helpers
  2. Verify the blob is a NebulaEncryptedData message and not truncated or a different protobuf type
  3. Regenerate the encrypted artifact with the current library version

Example fix

// before
ned := &cert.NebulaEncryptedData{Ciphertext: ct}
b, _ := proto.Marshal(ned) // EncryptionMetadata missing
// after
ned := &cert.NebulaEncryptedData{EncryptionMetadata: meta, Ciphertext: ct}
b, _ := proto.Marshal(ned)
Defensive patterns

Strategy: type-guard

Validate before calling

var rned cert.RawNebulaEncryptedData
if err := proto.Unmarshal(b, &rned); err != nil { return err }
if rned.EncryptionMetadata == nil { return fmt.Errorf("EncryptionMetadata missing") }

Type guard

func hasEncryptionMetadata(b []byte) bool {
    var r cert.RawNebulaEncryptedData
    if proto.Unmarshal(b, &r) != nil { return false }
    return r.EncryptionMetadata != nil
}

Try / catch

ned, err := cert.UnmarshalNebulaEncryptedData(b)
if err != nil {
    if strings.Contains(err.Error(), "EncryptionMetadata was nil") { /* malformed blob - re-encrypt */ }
    return err
}

Prevention

When it happens

Trigger: Calling UnmarshalNebulaEncryptedData with protobuf bytes that parse but contain no EncryptionMetadata field - e.g. a hand-built or partially serialized RawNebulaEncryptedData, or bytes of a different message type that happen to parse.

Common situations: Constructing NebulaEncryptedData manually in tests and forgetting to set EncryptionMetadata; deserializing a truncated or wrong-version blob; passing an unrelated protobuf message by mistake.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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