netbirdio/netbird · error
incompatible argon2 version
Error message
incompatible argon2 version
What it means
Sentinel error argon2id.ErrIncompatibleVersion (shared/hash/argon2id/argon2id.go:27), returned by decodeHash when the stored PHC string parses but its v= number differs from golang.org/x/crypto/argon2.Version (0x13, the only version this package produces and accepts). The verification is intentionally strict: the package will not attempt to verify hashes from other Argon2 versions.
Source
Thrown at shared/hash/argon2id/argon2id.go:27
"strings"
"golang.org/x/crypto/argon2"
)
const (
argon2Memory = 19456
argon2Iterations = 2
argon2Parallelism = 1
argon2SaltLength = 16
argon2KeyLength = 32
)
var (
// ErrInvalidHash is returned when the hash string format is invalid
ErrInvalidHash = errors.New("invalid hash format")
// ErrIncompatibleVersion is returned when the Argon2 version is not supported
ErrIncompatibleVersion = errors.New("incompatible argon2 version")
// ErrMismatchedHashAndPassword is returned when password verification fails
ErrMismatchedHashAndPassword = errors.New("password does not match hash")
)
func Hash(secret string) (string, error) {
salt := make([]byte, argon2SaltLength)
if _, err := rand.Read(salt); err != nil {
return "", fmt.Errorf("failed to generate salt: %w", err)
}
hash := argon2.IDKey(
[]byte(secret),
salt,
argon2Iterations,
argon2Memory,
argon2Parallelism,
argon2KeyLength,View on GitHub (pinned to 93e97f4bf1)
Solutions
- Re-hash the secret with this package (argon2id.Hash) and replace the stored value, since cross-version verification is unsupported
- If the hash comes from an import, verify it once with the originating library (if version-compatible semantics matter) and rehash on first successful login
- For tests, always generate fixtures with argon2id.Hash so the embedded version matches
Example fix
// before: imported hash with old argon2 version stored := "$argon2id$v=16$m=19456,t=2,p=1$...$..." // Verify -> incompatible argon2 version // after: reset/rehash with the current package stored, err := argon2id.Hash(password)
Defensive patterns
Strategy: fallback
Validate before calling
func hashVersion(encodedHash string) (int, error) {
parts := strings.Split(encodedHash, "$")
if len(parts) != 6 { return 0, argon2id.ErrInvalidHash }
var v int
if _, err := fmt.Sscanf(parts[2], "v=%d", &v); err != nil {
return 0, fmt.Errorf("%w: invalid version", argon2id.ErrInvalidHash)
}
return v, nil
} Try / catch
if err := argon2id.Verify(password, stored); err != nil {
if errors.Is(err, argon2id.ErrIncompatibleVersion) {
// cannot verify cross-version: fall back to reset/rehash flow
newHash, herr := argon2id.Hash(password)
if herr != nil { return herr }
return store.UpdateHash(userID, newHash) // requires authenticated reset or migration path
}
return err
} Prevention
- Generate all fixtures with the same argon2id package the verifier uses
- When importing external credentials, check the v= field first and route old-version records to a rehash-on-login path or a forced reset
- Pin golang.org/x/crypto across build and migration tooling so argon2.Version stays consistent
When it happens
Trigger: Calling argon2id.Verify against a hash generated with a different Argon2 version, e.g. v=16 (Argon2 v1.2-era tooling, passlib older settings, or a PHP/Python implementation writing v=16 hashes).
Common situations: Importing credential dumps from systems whose Argon2 library emits v=16; interoperating with frameworks whose default argon2 version differs; hand-constructed hash strings.
Related errors
- invalid hash format
- management client is not initialised
- profile not found
- watcher closed unexpectedly
- failed to verify signature of artifact keys
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/460154a62ef81743.
Report an issue: GitHub.