{"record":{"id":"620481d81bde9f7a","repo":"Mintplex-Labs/anything-llm","slug":"failed-to-generate-user-recovery-codes","errorCode":null,"errorMessage":"Failed to generate user recovery codes!","messagePattern":"Failed to generate user recovery codes!","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/utils/PasswordRecovery/index.js","lineNumber":28,"sourceCode":"  const newRecoveryCodes = [];\n  const plainTextCodes = [];\n  for (let i = 0; i < 4; i++) {\n    const code = v4();\n    const hashedCode = bcrypt.hashSync(code, 10);\n    newRecoveryCodes.push({\n      user_id: userId,\n      code_hash: hashedCode,\n    });\n    plainTextCodes.push(code);\n  }\n\n  const { error } = await RecoveryCode.createMany(newRecoveryCodes);\n  if (!!error) throw new Error(error);\n\n  const { user: success } = await User._update(userId, {\n    seen_recovery_codes: true,\n  });\n  if (!success) throw new Error(\"Failed to generate user recovery codes!\");\n\n  return plainTextCodes;\n}\n\nasync function recoverAccount(username = \"\", recoveryCodes = []) {\n  const user = await User.get({ username: String(username) });\n  if (!user) return { success: false, error: \"Invalid recovery codes.\" };\n\n  // If hashes do not exist for a user\n  // because this is a user who has not logged out and back in since upgrade.\n  const allUserHashes = await RecoveryCode.hashesForUser(user.id);\n  if (allUserHashes.length < 4)\n    return { success: false, error: \"Invalid recovery codes.\" };\n\n  const uniqueRecoveryCodes = [\n    ...new Set(\n      recoveryCodes\n        .map((code) => (typeof code === \"string\" ? code.trim() : \"\"))","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/server/utils/PasswordRecovery/index.js#L10-L46","documentation":"Thrown by generateRecoveryCodes after RecoveryCode.createMany succeeded but the subsequent User._update to set seen_recovery_codes=true returned a falsy success. Recovery codes were already persisted, yet the user row could not be marked, so the function aborts to avoid returning codes whose 'seen' flag is inconsistent. It indicates a user-level write failure, not a recovery-code write failure.","triggerScenarios":"The user record was deleted or its row locked between the two writes; the User model _update returned {user:false} due to a DB error or unknown user id; a concurrent session reset the user mid-flow.","commonSituations":"Account deletion racing with a login that triggers code generation; DB connection blip; passing a stale/invalid userId from a stale session token.","solutions":["Verify the userId passed to generateRecoveryCodes still exists in the users table at call time.","Inspect DB logs/errors around the User._update call for the underlying failure.","Treat this as a partial-write: the codes were created, so on retry ensure createMany is idempotent or clean up orphaned RecoveryCode rows for that user first.","If the user was deleted intentionally, stop calling generateRecoveryCodes for that id."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Confirm the user exists and is writable before generating codes.\nconst user = await User.get({ id: userId });\nif (!user) {\n  return { success: false, error: \"User not found; cannot generate recovery codes.\" };\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await generateRecoveryCodes(userId);\n} catch (e) {\n  if (/Failed to generate user recovery codes/i.test(e.message)) {\n    // Codes were persisted but the user flag was not — clean up to avoid orphan rows.\n    await RecoveryCode.deleteMany({ user_id: userId }).catch(() => {});\n    return { success: false, error: \"Could not finalize recovery codes; please retry.\" };\n  }\n  throw e;\n}","preventionTips":["Pass a fresh userId obtained from the authenticated session, not a cached value.","Wrap code generation in a transaction or compensate on failure (delete the just-created codes).","Log the underlying User._update failure for diagnosis."],"tags":["password-recovery","database","state","partial-write"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}