slackhq/nebula · error

encoded Argon2Parameters was nil

Error message

encoded Argon2Parameters was nil

What it means

Within EncryptionMetadata, the Argon2Parameters sub-message must be present; it defines how the passphrase is stretched into the AES key. When the decoded message has EncryptionMetadata but a nil Argon2Parameters, the library cannot derive the key and fails with this error.

Solutions

  1. Populate Argon2Parameters (version, memory, parallelism, iterations, salt) in EncryptionMetadata before marshalling on the encrypting side
  2. Re-encrypt using EncryptAndMarshalSigningPrivateKey / EncryptAndMarshalCert which always set Argon2Parameters
  3. If the data came from another tool, confirm it writes the full nebula encrypted-data format

Example fix

// before
meta := &cert.EncryptionMetadata{Nonce: nonce}
// after
meta := &cert.EncryptionMetadata{Nonce: nonce, Argon2Parameters: &cert.RawNebulaArgon2Parameters{Version: argon2.Version, Memory: 2*1024*1024, Parallelism: 4, Iterations: 1, Salt: salt}}
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: Calling UnmarshalNebulaEncryptedData on data whose EncryptionMetadata was serialized without its Argon2Parameters field set (proto3 omits empty sub-messages), e.g. a partially populated NebulaEncryptedData built by hand or by an incomplete external implementation.

Common situations: Hand-assembling EncryptionMetadata with only the nonce; an external tool serializing a subset of fields; truncation of the message dropping the sub-message field.

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/b9d936e36ccf8eb1. Report an issue: GitHub.

Appendix: source

Thrown at cert/crypto.go:210

// 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,
	}

	return &ned, nil
}

View on GitHub (pinned to dd8f660c0a)