ory/hydra · error
ErrInvalidHash
ErrInvalidHash
Error message
the encoded hash is not in the correct format
What it means
ErrInvalidHash indicates the encoded password hash string does not match the expected PHC/modular-crypt format for its algorithm (wrong field count, malformed base64, unparsable parameters). decodeArgon2idHash/decodePbkdf2Hash return it, and CompareArgon2id/CompareArgon2i/Compare also raise it when decoded parameters are out of range (e.g. Memory > math.MaxUint32).
Source
Thrown at oryx/hasherx/hasher_argon2.go:24
"crypto/rand"
"encoding/base64"
"fmt"
"math"
"time"
"github.com/ory/x/otelx"
"github.com/inhies/go-bytesize"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"github.com/pkg/errors"
"golang.org/x/crypto/argon2"
)
var (
ErrInvalidHash = errors.New("the encoded hash is not in the correct format")
ErrIncompatibleVersion = errors.New("incompatible version of argon2")
ErrMismatchedHashAndPassword = errors.New("passwords do not match")
)
type (
// Argon2Config is the configuration for a Argon2 hasher.
Argon2Config struct {
// Memory is the amount of memory to use.
Memory bytesize.ByteSize `json:"memory"`
// Iterations is the number of iterations to use.
Iterations uint32 `json:"iterations"`
// Parallelism is the number of threads to use.
Parallelism uint8 `json:"parallelism"`
// SaltLength is the length of the salt to use.
SaltLength uint32 `json:"salt_length"`View on GitHub (pinned to 4174065ffb)
Solutions
- Verify the stored hash is complete and matches the expected format, e.g. $argon2id$v=19$m=65536,t=3,p=4$<salt>$<hash> with valid base64 segments.
- Regenerate the hash with the library's own Hasher/Generate function and re-store it.
- Check DB column length/encoding so the hash is not truncated or transformed in transit.
- Clamp or fix generation parameters so Memory fits in uint32 (< 4294967296 KiB).
Example fix
// before hash := user.PasswordHash[:32] // truncated in log copy err := hasherx.Compare(ctx, pw, []byte(hash)) // ErrInvalidHash // after err := hasherx.Compare(ctx, pw, []byte(user.PasswordHash)) // full stored value
Defensive patterns
Strategy: validation
Validate before calling
func looksLikePHCHash(s string) bool {
return strings.Count(s, "$") >= 5 && strings.HasPrefix(s, "$argon2") || strings.HasPrefix(s, "$pbkdf2")
}
// verify stored hash shape and length before Compare Type guard
func isParseableArgon2Hash(h []byte) bool {
return strings.HasPrefix(string(h), "$argon2id$") || strings.HasPrefix(string(h), "$argon2i$")
} Try / catch
if err := hasherx.Compare(ctx, pw, hash); err != nil {
if errors.Is(err, hasherx.ErrInvalidHash) {
// corrupt/truncated hash: force password reset, log the account
return ErrCorruptCredentialRecord
}
return err
} Prevention
- Use DB columns long enough for the full PHC string (>=256 chars)
- Avoid re-encoding hashes through JSON/base64 transforms
- Generate hashes with the library's own Hasher to guarantee format
- Validate argon2 Memory fits uint32 at config time
When it happens
Trigger: Calling CompareArgon2id/CompareArgon2i/ComparePbkdf2 (or Compare dispatching to them) with a hash string whose segments cannot be parsed — missing '$' fields, corrupt base64 parts — or whose decoded argon2 memory parameter exceeds math.MaxUint32 (hash_comparator.go:59/84).
Common situations: Hashes truncated by a fixed-width DB column, hashes re-encoded through JSON/base64 round trips, hand-written fixture hashes with wrong parameter ordering, or hashes generated by tools with memory settings that overflow the uint32 check.
Related errors
- ErrUnknownHashAlgorithm
- ErrMismatchedHashAndPassword
- ErrIncompatibleVersion
- cookiex: at least one secret is required
- invalid elliptic curve key size, this algorithm does not sup
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/a0d57e45a26e0536.
Report an issue: GitHub.