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

  1. Re-hash affected credentials with the current argon2id implementation (progressive migration: on next successful login with a legacy verifier, store a fresh hash).
  2. Use a verifier that supports the old v=16 version for legacy hashes, then upgrade.
  3. 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

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.