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.

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)

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.