siyuan-note/siyuan · error

Argon2id Parallelism must be between 1 and 16

Error message

Argon2id Parallelism must be between 1 and 16

What it means

ValidateArgon2Params requires Parallelism (number of Argon2id lanes/threads) to be between 1 and 16 inclusive. Zero would be invalid input to the Argon2 function and oversized values could oversubscribe CPUs, so both are rejected.

Solutions

  1. Set Parallelism to a value in 1-16; util.DefaultArgon2Params() uses 4
  2. Unmarshal the config into a struct pre-populated with util.DefaultArgon2Params() so a missing 'parallelism' key doesn't yield 0
  3. Cap parallelism from runtime.NumCPU() at 16 before validating

Example fix

// before
p := util.Argon2Params{Memory: 64 * 1024, Iterations: 3, KeyLength: 32} // Parallelism zero

// after
p := util.Argon2Params{Memory: 64 * 1024, Iterations: 3, Parallelism: 4, KeyLength: 32}
Defensive patterns

Strategy: validation

Validate before calling

if p.Parallelism == 0 || p.Parallelism > 16 {
    return fmt.Errorf("parallelism must be 1-16, got %d", p.Parallelism)
}

Try / catch

if _, err := util.ValidateArgon2Params(p); err != nil {
    return fmt.Errorf("invalid KDF params: %w", err)
}

Prevention

When it happens

Trigger: Calling ValidateArgon2Params (directly or via EnableEncryptedNotebook, ImportNotebookCryptoBackup, deriveKEK, or backup-restore paths) with Argon2Params.Parallelism == 0 or > 16 — commonly a zero-value struct where Parallelism was never set.

Common situations: Constructing Argon2Params without setting Parallelism (uint8 zero value), deserializing a config JSON that lacks the 'parallelism' key, or copying parallelism from a machine with many cores (e.g. 32 threads).

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/84b181983ebcdbdf. Report an issue: GitHub.

Appendix: source

Thrown at kernel/util/kdf.go:80

// 或过弱参数降低安全性。
func ValidateArgon2Params(p Argon2Params) (Argon2Params, error) {
	if p.KeyLength != 32 {
		return p, errors.New("Argon2id KeyLength must be 32")
	}
	if p.Memory < 64*1024 {
		return p, errors.New("Argon2id Memory too low (minimum 64 MB)")
	}
	if p.Memory > 256*1024 {
		return p, errors.New("Argon2id Memory too high (maximum 256 MB)")
	}
	if p.Iterations < 3 {
		return p, errors.New("Argon2id Iterations too low (minimum 3)")
	}
	if p.Iterations > 10 {
		return p, errors.New("Argon2id Iterations too high (maximum 10)")
	}
	if p.Parallelism == 0 || p.Parallelism > 16 {
		return p, errors.New("Argon2id Parallelism must be between 1 and 16")
	}
	return p, nil
}

// DeriveKey 用 Argon2id 从密码派生密钥。同一 password+salt+params 多次调用结果一致。
func DeriveKey(password string, salt []byte, p Argon2Params) []byte {
	return argon2.IDKey([]byte(password), salt, p.Iterations, p.Memory, p.Parallelism, p.KeyLength)
}

// Encrypt 用 AES-256-GCM 加密。每次调用生成随机 nonce,因此同一明文多次加密结果不同。
// 返回格式:magic(4B) || spec(1B) || algorithm(1B) || nonceLength(1B) || nonce || ciphertext || GCM tag(16B)。
func Encrypt(key, plaintext []byte) ([]byte, error) {
	return encryptGCM(key, plaintext, nil, "Encrypt")
}

// Decrypt 对应 Encrypt 的解密。密钥错误、格式无效或密文被篡改时返回错误。
func Decrypt(key, ciphertext []byte) ([]byte, error) {
	return decryptGCM(key, ciphertext, nil, "Decrypt")

View on GitHub (pinned to 9f775e8a12)