{"record":{"id":"7ca569573140fa96","repo":"ruvnet/ruflo","slug":"hash-failed","errorCode":"HASH_FAILED","errorMessage":"Failed to hash password","messagePattern":"Failed to hash password","errorType":"exception","errorClass":"PasswordHashError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/security/src/password-hasher.ts","lineNumber":193,"sourceCode":"   * @param password - The plaintext password to hash\n   * @returns The bcrypt hash\n   * @throws PasswordHashError if password is invalid\n   */\n  async hash(password: string): Promise<string> {\n    const validation = this.validate(password);\n\n    if (!validation.isValid) {\n      throw new PasswordHashError(\n        validation.errors.join('; '),\n        'VALIDATION_FAILED'\n      );\n    }\n\n    try {\n      // bcrypt automatically generates a random salt per hash\n      return await bcrypt.hash(password, this.config.rounds);\n    } catch (error) {\n      throw new PasswordHashError(\n        'Failed to hash password',\n        'HASH_FAILED'\n      );\n    }\n  }\n\n  /**\n   * Verifies a password against a bcrypt hash.\n   * Uses timing-safe comparison internally.\n   *\n   * @param password - The plaintext password to verify\n   * @param hash - The bcrypt hash to compare against\n   * @returns True if password matches, false otherwise\n   */\n  async verify(password: string, hash: string): Promise<boolean> {\n    if (!password || !hash) {\n      return false;\n    }","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/security/src/password-hasher.ts#L175-L211","documentation":"hash() wraps the bcryptjs bcrypt.hash() call in try/catch; any underlying failure (not policy-related) is rethrown as PasswordHashError with code HASH_FAILED and the static message 'Failed to hash password'. This indicates the crypto call itself blew up, not the input policy.","triggerScenarios":"Passing a non-string password from untyped JS (bcryptjs throws on null/undefined/number); a corrupted or partially installed bcryptjs package after the #1608 bcrypt->bcryptjs swap; rounds misconfigured outside bcryptjs limits (the constructor already clamps to 10-20, so this only happens with a mutated config object).","commonSituations":"Callers bypassing TypeScript types with null from req.body.password; a stale node_modules after switching dependencies between bcrypt and bcryptjs; CI caching a broken native/JS build of the hash library.","solutions":["Guarantee password is a non-null string before calling hash() (typeof password === 'string').","Log the caught error in the surrounding handler — this wrapper swallows the original message, so capture err.code and rethrow with cause if you control the call site.","Reinstall dependencies (rm -rf node_modules && npm install) if the bcryptjs module itself fails to load or execute.","Verify the hasher instance was built with rounds between 10 and 20."],"exampleFix":"// before\nconst hash = await hasher.hash(req.body.password); // req.body.password may be null\n\n// after\nconst raw = req.body?.password;\nif (typeof raw !== 'string') throw new PasswordHashError('password must be a string', 'VALIDATION_FAILED');\nconst hash = await hasher.hash(raw);","handlingStrategy":"try-catch","validationCode":"if (typeof password !== 'string' || password.length === 0) {\n  throw new TypeError('password must be a non-empty string');\n}","typeGuard":"function isHashablePassword(pw: unknown): pw is string {\n  return typeof pw === 'string' && pw.length > 0;\n}","tryCatchPattern":"try {\n  return await hasher.hash(password);\n} catch (err) {\n  if (err instanceof PasswordHashError && err.code === 'HASH_FAILED') {\n    logger.error({ err }, 'bcrypt failure'); // wrapper hides cause: log and rethrow as 500\n    throw new InternalError('password hashing unavailable');\n  }\n  throw err;\n}","preventionTips":["Never call hash() with unvalidated external input; assert string type at the boundary.","Pin bcryptjs in package.json and lockfile to avoid half-migrated installs after the bcrypt->bcryptjs switch (#1608).","Treat HASH_FAILED as an infrastructure error (500/log), never as user feedback."],"tags":["bcrypt","hashing","security","runtime"],"backgroundTag":"password-hash-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}