{"record":{"id":"a0d57e45a26e0536","repo":"ory/hydra","slug":"errinvalidhash","errorCode":"ErrInvalidHash","errorMessage":"the encoded hash is not in the correct format","messagePattern":"the encoded hash is not in the correct format","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"oryx/hasherx/hasher_argon2.go","lineNumber":24,"sourceCode":"\t\"crypto/rand\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"math\"\n\t\"time\"\n\n\t\"github.com/ory/x/otelx\"\n\n\t\"github.com/inhies/go-bytesize\"\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/codes\"\n\n\t\"github.com/pkg/errors\"\n\t\"golang.org/x/crypto/argon2\"\n)\n\nvar (\n\tErrInvalidHash               = errors.New(\"the encoded hash is not in the correct format\")\n\tErrIncompatibleVersion       = errors.New(\"incompatible version of argon2\")\n\tErrMismatchedHashAndPassword = errors.New(\"passwords do not match\")\n)\n\ntype (\n\t// Argon2Config is the configuration for a Argon2 hasher.\n\tArgon2Config struct {\n\t\t// Memory is the amount of memory to use.\n\t\tMemory bytesize.ByteSize `json:\"memory\"`\n\n\t\t// Iterations is the number of iterations to use.\n\t\tIterations uint32 `json:\"iterations\"`\n\n\t\t// Parallelism is the number of threads to use.\n\t\tParallelism uint8 `json:\"parallelism\"`\n\n\t\t// SaltLength is the length of the salt to use.\n\t\tSaltLength uint32 `json:\"salt_length\"`","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/oryx/hasherx/hasher_argon2.go#L6-L42","documentation":"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).","triggerScenarios":"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).","commonSituations":"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.","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)."],"exampleFix":"// before\nhash := user.PasswordHash[:32] // truncated in log copy\nerr := hasherx.Compare(ctx, pw, []byte(hash)) // ErrInvalidHash\n// after\nerr := hasherx.Compare(ctx, pw, []byte(user.PasswordHash)) // full stored value","handlingStrategy":"validation","validationCode":"func looksLikePHCHash(s string) bool {\n  return strings.Count(s, \"$\") >= 5 && strings.HasPrefix(s, \"$argon2\") || strings.HasPrefix(s, \"$pbkdf2\")\n}\n// verify stored hash shape and length before Compare","typeGuard":"func isParseableArgon2Hash(h []byte) bool {\n  return strings.HasPrefix(string(h), \"$argon2id$\") || strings.HasPrefix(string(h), \"$argon2i$\")\n}","tryCatchPattern":"if err := hasherx.Compare(ctx, pw, hash); err != nil {\n  if errors.Is(err, hasherx.ErrInvalidHash) {\n    // corrupt/truncated hash: force password reset, log the account\n    return ErrCorruptCredentialRecord\n  }\n  return err\n}","preventionTips":["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"],"tags":["passwords","hashing","crypto","format"],"backgroundTag":"invalid-hash-format","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}