Mintplex-Labs/anything-llm · warning
Invalid password.
Error message
Invalid password.
What it means
resetPassword() trims the new password and throws when the result is empty — i.e. the user submitted no password or one made only of whitespace. Deeper password policy (JOI rules) is enforced later inside User.update, so this specific throw is purely the empty-input guard.
Solutions
- Require a non-empty new password in the UI before submitting the reset request
- Pass a real password string as the second argument (it defaults to '' when omitted)
- Trim client-side too so whitespace-only input is rejected early
- Catch the throw and map it to a 400-style form error rather than a 500
Defensive patterns
Strategy: validation
Validate before calling
const newPassword = String(rawPassword ?? '').trim();
if (!newPassword) return res.status(400).json({ message: 'Password is required.' });
// only now call resetPassword(token, newPassword, confirmPassword) Type guard
function isValidPasswordInput(pw) {
return typeof pw === 'string' && pw.trim().length > 0;
} Try / catch
try {
await resetPassword(token, newPassword, confirmPassword);
} catch (err) {
if (err.message === 'Invalid password.') return res.status(400).json({ message: 'Enter a new password.' });
throw err;
} Prevention
- Make the new-password field required in the reset form before submit
- Trim inputs client-side so whitespace-only values never reach the API
- Map this throw to a 400 response, not a 500, in route handlers
When it happens
Trigger: Calling resetPassword(token, '', '') or with a whitespace-only new password — e.g. the reset form was submitted with the password field blank.
Common situations: Frontend form validation missing/gapped so empty submissions reach the API; automated calls passing undefined defaults ('' is the default for both params); test harnesses calling the function without arguments.
Related errors
- Passwords do not match
- Content must be a non-empty string
- Empty entry
- No text to predict on.
- No valid user IDs provided.
AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18).
Data as JSON: /api/errors/460a757d67548802.
Report an issue: GitHub.
Appendix: source
Thrown at server/utils/PasswordRecovery/index.js:73
const index = unmatchedHashes.findIndex((hash) =>
bcrypt.compareSync(code, hash)
);
if (index === -1) return false;
unmatchedHashes.splice(index, 1);
return true;
});
if (!validCodes) return { success: false, error: "Invalid recovery codes." };
const { passwordResetToken, error } = await PasswordResetToken.create(
user.id
);
if (!!error) return { success: false, error };
return { success: true, resetToken: passwordResetToken.token };
}
async function resetPassword(token, _newPassword = "", confirmPassword = "") {
const newPassword = String(_newPassword).trim(); // No spaces in passwords
if (!newPassword) throw new Error("Invalid password.");
if (newPassword !== String(confirmPassword))
throw new Error("Passwords do not match");
const resetToken = await PasswordResetToken.findUnique({
token: String(token),
});
if (!resetToken || resetToken.expiresAt < new Date()) {
return { success: false, message: "Invalid reset token" };
}
// JOI password rules will be enforced inside .update.
const { error } = await User.update(resetToken.user_id, {
password: newPassword,
});
// seen_recovery_codes is not publicly writable
// so we have to do direct update here
await User._update(resetToken.user_id, {View on GitHub (pinned to 3aec848f28)