slackhq/nebula · error

incompatible Argon2 version: %d

Error message

incompatible Argon2 version: %d

What it means

deriveKey checks that the Argon2Parameters version matches the argon2.Version the library was compiled against (argon2id, version 0x13). A mismatch means the stored/constructed KDF parameters came from an incompatible Argon2 variant (argon2i/argon2d or a different version byte).

Source

Thrown at cert/crypto.go:131

		params.salt = make([]byte, 32)
		if _, err := rand.Read(params.salt); err != nil {
			return nil, err
		}
	}

	// keySize of 32 bytes will result in AES-256 encryption
	key, err := deriveKey(passphrase, 32, params)
	if err != nil {
		return nil, err
	}

	return key, nil
}

// Derives a key from a passphrase using Argon2id
func deriveKey(passphrase []byte, keySize uint32, params *Argon2Parameters) ([]byte, error) {
	if params.version != argon2.Version {
		return nil, fmt.Errorf("incompatible Argon2 version: %d", params.version)
	}

	if params.salt == nil {
		return nil, fmt.Errorf("salt must be set in argon2Parameters")
	} else if len(params.salt) < 16 {
		return nil, fmt.Errorf("salt must be at least 128  bits")
	}

	key := argon2.IDKey(passphrase, params.salt, params.Iterations, params.Memory, params.Parallelism, keySize)

	return key, nil
}

// Prepends nonce to ciphertext
func joinNonceCiphertext(nonce []byte, ciphertext []byte) []byte {
	return append(nonce, ciphertext...)
}

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Create parameters with NewArgon2Parameters(memory, parallelism, iterations) so the correct version is set.
  2. If the blob came from another tool, re-encrypt the key with this library's EncryptAndMarshalSigningPrivateKey.
  3. Align library versions between encrypting and decrypting parties.

Example fix

// before
params := &cert.Argon2Parameters{Memory: 9k...} // version left zero-value
// after
params := cert.NewArgon2Parameters(9*1024, 1, 4) // sets version = argon2.Version
Defensive patterns

Strategy: validation

Validate before calling

// always construct parameters via the constructor so version is set correctly
params := cert.NewArgon2Parameters(9*1024, 1, 4) // version := argon2.Version (0x13)

Try / catch

if err != nil && strings.Contains(err.Error(), "incompatible Argon2 version") {
    return fmt.Errorf("encrypted key was produced with an incompatible Argon2 variant; re-encrypt with this library")
}

Prevention

When it happens

Trigger: Decrypting (or deriving with) parameters whose params.version was set manually or deserialized from data produced by a different Argon2 version — note Argon2Parameters.version is unexported, so this only happens via NewArgon2Parameters mishandling or crafted/edited encrypted blobs.

Common situations: Hand-editing encrypted key metadata, cross-version decryption between forks that used different argon2 libraries, or tests constructing Argon2Parameters without NewArgon2Parameters.

Related errors


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