ory/kratos · error · ErrHashParametersOutOfBounds

firescrypt r= not in [1, ]

Error message

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

What it means

This error means a Firebase scrypt hash declares an r (block size) parameter outside the valid range [1, 8]. r=0 is invalid because the scrypt memory cost 128*N*r would be zero; r>8 exceeds the RFC 7914 standard block size and would inflate memory use beyond the package's bounds. It wraps ErrHashParametersOutOfBounds from validateFirebaseScryptParams during hash decode.

Solutions

  1. Inspect the r field in the hash string and ensure it is an integer in [1, 8] (Firebase uses r=8)
  2. Regenerate or re-export the hash with the standard r=8
  3. If the hash is corrupted, re-hash the password from its source rather than repairing the string by hand

Example fix

// before (r=0, invalid)
$firescrypt$ln=14$r=0$p=1$...
// after (r=8, valid)
$firescrypt$ln=14$r=8$p=1$...
Defensive patterns

Strategy: validation

Validate before calling

func firebaseScryptROK(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("invalid firescrypt r: %w", err)
}

Prevention

When it happens

Trigger: decodeFirebaseScryptHash encounters a $firescrypt hash string with r=0 or r>8 in its parameters, either via ValidateImportedHash on import or during password comparison.

Common situations: Malformed or hand-crafted hash strings with missing/zero parameters; hashes exported from tools using non-standard scrypt block sizes; typo when manually constructing a hash for seeding test users.

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

Appendix: source

Thrown at hash/hash_limits.go:84

	// maxPbkdf2Iterations bounds PBKDF2 i. OWASP 2023 recommends 600k
	// (SHA-256) / 210k (SHA-512). 10M ≈ 10× the strongest published
	// recommendation and bounds CPU to a few seconds on modern hardware.
	maxPbkdf2Iterations uint32 = 10_000_000

	// maxBcryptCost bounds bcrypt cost. The format spec allows 4–31, but
	// cost grows exponentially: cost 12 (Kratos, PHP, Django default) is
	// ~250 ms; cost 14 (high-security guidance) is ~1 s; cost 15 (practical
	// max for interactive use) is ~2 s; cost 17 is ~8 s. No mainstream
	// platform defaults above cost 12.
	maxBcryptCost = 15
)

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

View on GitHub (pinned to b86338da04)