{"record":{"id":"460154a62ef81743","repo":"netbirdio/netbird","slug":"incompatible-argon2-version","errorCode":null,"errorMessage":"incompatible argon2 version","messagePattern":"incompatible argon2 version","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/hash/argon2id/argon2id.go","lineNumber":27,"sourceCode":"\t\"strings\"\n\n\t\"golang.org/x/crypto/argon2\"\n)\n\nconst (\n\targon2Memory      = 19456\n\targon2Iterations  = 2\n\targon2Parallelism = 1\n\targon2SaltLength  = 16\n\targon2KeyLength   = 32\n)\n\nvar (\n\t// ErrInvalidHash is returned when the hash string format is invalid\n\tErrInvalidHash = errors.New(\"invalid hash format\")\n\n\t// ErrIncompatibleVersion is returned when the Argon2 version is not supported\n\tErrIncompatibleVersion = errors.New(\"incompatible argon2 version\")\n\n\t// ErrMismatchedHashAndPassword is returned when password verification fails\n\tErrMismatchedHashAndPassword = errors.New(\"password does not match hash\")\n)\n\nfunc Hash(secret string) (string, error) {\n\tsalt := make([]byte, argon2SaltLength)\n\tif _, err := rand.Read(salt); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to generate salt: %w\", err)\n\t}\n\n\thash := argon2.IDKey(\n\t\t[]byte(secret),\n\t\tsalt,\n\t\targon2Iterations,\n\t\targon2Memory,\n\t\targon2Parallelism,\n\t\targon2KeyLength,","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/shared/hash/argon2id/argon2id.go#L9-L45","documentation":"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.","triggerScenarios":"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).","commonSituations":"Importing credential dumps from systems whose Argon2 library emits v=16; interoperating with frameworks whose default argon2 version differs; hand-constructed hash strings.","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"],"exampleFix":"// before: imported hash with old argon2 version\nstored := \"$argon2id$v=16$m=19456,t=2,p=1$...$...\" // Verify -> incompatible argon2 version\n\n// after: reset/rehash with the current package\nstored, err := argon2id.Hash(password)","handlingStrategy":"fallback","validationCode":"func hashVersion(encodedHash string) (int, error) {\n    parts := strings.Split(encodedHash, \"$\")\n    if len(parts) != 6 { return 0, argon2id.ErrInvalidHash }\n    var v int\n    if _, err := fmt.Sscanf(parts[2], \"v=%d\", &v); err != nil {\n        return 0, fmt.Errorf(\"%w: invalid version\", argon2id.ErrInvalidHash)\n    }\n    return v, nil\n}","typeGuard":null,"tryCatchPattern":"if err := argon2id.Verify(password, stored); err != nil {\n    if errors.Is(err, argon2id.ErrIncompatibleVersion) {\n        // cannot verify cross-version: fall back to reset/rehash flow\n        newHash, herr := argon2id.Hash(password)\n        if herr != nil { return herr }\n        return store.UpdateHash(userID, newHash) // requires authenticated reset or migration path\n    }\n    return err\n}","preventionTips":["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"],"tags":["go","argon2","hashing","version-compat","password"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}