ory/hydra · error
ErrIncompatibleVersion
ErrIncompatibleVersion
Error message
incompatible version of argon2
What it means
Argon2 hashes embed a version field (v=19 for argon2 0x13). decodeArgon2idHash returns ErrIncompatibleVersion when the version encoded in the hash differs from the argon2.Version the x/crypto package implements, because the reference implementation cannot safely verify against an unknown version.
Source
Thrown at oryx/hasherx/hasher_argon2.go:25
"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
- Re-hash affected credentials with the current argon2id implementation (progressive migration: on next successful login with a legacy verifier, store a fresh hash).
- Use a verifier that supports the old v=16 version for legacy hashes, then upgrade.
- Audit hash generation settings to ensure all new hashes use the default current version (v=19).
Example fix
// before
// stored: $argon2id$v=16$m=65536,t=3,p=4$...
err := hasherx.Compare(ctx, pw, legacyHash) // ErrIncompatibleVersion
// after
ok := legacyVerifier(legacyHash, pw)
if ok {
newHash, _ := argon2Hasher.Generate(ctx, pw) // v=19
store(user, newHash)
} Defensive patterns
Strategy: type-guard
Validate before calling
func isCurrentArgon2Version(hash string) bool {
i := strings.Index(hash, "v=")
if i < 0 { return false }
v, err := strconv.Atoi(strings.SplitN(hash[i+2:], "$", 2)[0])
return err == nil && v == argon2.Version
} Try / catch
if err := hasherx.Compare(ctx, pw, hash); err != nil {
if errors.Is(err, hasherx.ErrIncompatibleVersion) {
return upgradeLegacyHash(user, pw) // verify with legacy lib, rehash v=19
}
return err
} Prevention
- Standardize on argon2 v=19 (current x/crypto default) for all new hashes
- During migrations, verify legacy v=16 hashes with a compatible verifier then re-hash
- Record hash scheme/version metadata alongside credentials
When it happens
Trigger: Calling Compare (dispatching to argon2) or decodeArgon2idHash with a hash string carrying v=16 (argon2 0x10) or any non-0x13 version; the check `version != argon2.Version` at hash_comparator.go:154 fails.
Common situations: Hashes generated years ago with argon2 v1.0 (0x10) and now verified with current x/crypto (0x13 only); hashes produced by other languages/tools defaulting to a different version; migration from an older hasherx/x/crypto dependency.
Related errors
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/3c1f6bb1b225bfca.
Report an issue: GitHub.