ory/kratos · error · ErrHashParametersOutOfBounds

scrypt r= not in [1, ]

Error message

scrypt r=%d not in [1, %d]

What it means

This error means a plain scrypt hash declares an r (block size) parameter outside the valid range [1, 8]. r=0 makes the memory cost zero; r>8 exceeds the RFC 7914 block size and would push per-compare memory beyond the package's 128 MiB cap when combined with high N. It wraps ErrHashParametersOutOfBounds from validateScryptParams.

Solutions

  1. Check the r value in the hash string; it must be in [1, 8] (RFC 7914 and all OWASP configs use r=8)
  2. Regenerate the hash with r=8 if it was produced by a non-standard tool
  3. Never hand-edit hash parameters; re-hash from the original password when possible

Example fix

// before (r=16, rejected)
$scrypt$N=131072$r=16$p=1$...
// after (r=8, accepted)
$scrypt$N=131072$r=8$p=1$...
Defensive patterns

Strategy: validation

Validate before calling

func scryptROK(r uint32) bool { return r >= 1 && r <= 8 }
// Or pre-validate the whole hash: hash.ValidateImportedHash(hashed)

Try / catch

if err := hash.ValidateImportedHash(raw); errors.Is(err, hash.ErrHashParametersOutOfBounds) {
    return fmt.Errorf("scrypt r out of range: %w", err)
}

Prevention

When it happens

Trigger: decodeScryptHash parses a scrypt hash whose r parameter is 0 or greater than 8, on import (ValidateImportedHash) or during password comparison.

Common situations: Hashes produced by tools that allow r>8 (some file-encryption setups use r=16); corrupt or hand-modified hash strings; mixing parameter conventions between firebase-scrypt and plain scrypt exports.

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 ory/kratos@b86338da04 (2026-09-07). Data as JSON: /api/errors/985f5f5ec7d66a14. Report an issue: GitHub.

Appendix: source

Thrown at hash/hash_limits.go:97

func validateFirebaseScryptParams(logN, r, p uint32) error {
	if logN > maxScryptLogN {
		return errors.Wrapf(ErrHashParametersOutOfBounds, "firescrypt ln=%d exceeds max %d", logN, maxScryptLogN)
	}
	if r == 0 || r > maxScryptR {
		return errors.Wrapf(ErrHashParametersOutOfBounds, "firescrypt r=%d not in [1, %d]", r, maxScryptR)
	}
	if p == 0 || p > maxScryptP {
		return errors.Wrapf(ErrHashParametersOutOfBounds, "firescrypt p=%d not in [1, %d]", p, maxScryptP)
	}
	return nil
}

func validateScryptParams(n, r, p uint32) error {
	if n == 0 || n > maxScryptN {
		return errors.Wrapf(ErrHashParametersOutOfBounds, "scrypt N=%d not in [1, %d]", n, maxScryptN)
	}
	if r == 0 || r > maxScryptR {
		return errors.Wrapf(ErrHashParametersOutOfBounds, "scrypt r=%d not in [1, %d]", r, maxScryptR)
	}
	if p == 0 || p > maxScryptP {
		return errors.Wrapf(ErrHashParametersOutOfBounds, "scrypt p=%d not in [1, %d]", p, maxScryptP)
	}
	return nil
}

func validateArgon2Params(memoryKiB uint64, iterations uint32, parallelism uint8) error {
	if memoryKiB == 0 || memoryKiB > uint64(maxArgon2MemoryKiB) {
		return errors.Wrapf(ErrHashParametersOutOfBounds, "argon2 m=%d KiB not in [1, %d]", memoryKiB, maxArgon2MemoryKiB)
	}
	if iterations == 0 || iterations > maxArgon2Iterations {
		return errors.Wrapf(ErrHashParametersOutOfBounds, "argon2 t=%d not in [1, %d]", iterations, maxArgon2Iterations)
	}
	if parallelism == 0 || parallelism > maxArgon2Parallelism {
		return errors.Wrapf(ErrHashParametersOutOfBounds, "argon2 p=%d not in [1, %d]", parallelism, maxArgon2Parallelism)
	}
	return nil

View on GitHub (pinned to b86338da04)