Mintplex-Labs/anything-llm · error
Username must start with a lowercase letter and only…
Error message
Username must start with a lowercase letter and only contain lowercase letters, numbers, underscores, hyphens, and periods
What it means
Thrown when the username passes both length checks but fails User.usernameRegex (/^[a-z][a-z0-9._@-]*$/): it must start with a lowercase letter and may then contain only lowercase letters, digits, periods, underscores, @ signs, and hyphens. It is a pre-database validator, so the write is rejected before Prisma runs. Uppercase letters, spaces, leading digits or hyphens, and non-ASCII characters are the usual offenders even though the message text omits @. Like the length check, User.update skips it when the username is unchanged.
Solutions
- Lowercase the username and strip spaces/invalid characters before submitting
- Reject leading digits, hyphens, and underscores client-side: the first character must be a lowercase letter
- Encode display names during LDAP/SSO sync (spaces to hyphens, drop uppercase) before calling create/update
- Validate locally against the exact pattern: /^[a-z][a-z0-9._@-]*$/ with 2-64 total characters
Example fix
// before
await User.create({ username: "John.Smith", password: hash });
// after
await User.create({ username: "john.smith", password: hash }); Defensive patterns
Strategy: validation
Validate before calling
const USERNAME_RE = /^[a-z][a-z0-9._@-]*$/;
function normalizeUsername(raw) {
return String(raw ?? "").trim().toLowerCase();
}
const username = normalizeUsername(input.username);
if (!username || !USERNAME_RE.test(username) || username.length < 2) {
return res.status(400).json({ error: "Invalid username format" });
} Try / catch
try {
await user.update(userId, { username });
} catch (e) {
if (/Username must start with/i.test(e.message)) return res.status(400).json({ error: e.message });
throw e;
} Prevention
- Autolowercase and trim username input in the UI before submit
- Mirror the server pattern with the input's pattern attribute
- Map display names to slug-style usernames during provisioning
When it happens
Trigger: User.create with "John" or "John.Smith" (leading uppercase); "1user", "-john", or "_john" (first character is not a lowercase letter); "john smith" (embedded space); usernames with Unicode letters or pasted invisible whitespace.
Common situations: Signup or admin forms that do not lowercase or restrict the input; LDAP/SSO sync using display names like "Jane Doe"; migrating users from a system that allowed uppercase; copy-paste introducing trailing spaces or newlines.
Related errors
- Username must be at least 2 characters
- Bio cannot be longer than 1,000 characters
- Daily message limit must be null or a number greater than…
- Invalid role. Allowed roles are
- addToWorkspaces must be a string of comma-separated…
AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18).
Data as JSON: /api/errors/2a0b16473245f2c3.
Report an issue: GitHub.
Appendix: source
Thrown at server/models/user.js:43
"dailyMessageLimit",
"bio",
],
validations: {
/**
* Unix-style username regex:
* - Must start with a lowercase letter
* - Can contain lowercase letters, digits, underscores, hyphens, @ signs, and periods
* - 2-64 characters long
*/
username: (newValue = "") => {
try {
const username = String(newValue);
if (username.length > 64)
throw new Error("Username cannot be longer than 64 characters");
if (username.length < 2)
throw new Error("Username must be at least 2 characters");
if (!User.usernameRegex.test(username))
throw new Error(
"Username must start with a lowercase letter and only contain lowercase letters, numbers, underscores, hyphens, and periods"
);
return username;
} catch (e) {
throw new Error(e.message);
}
},
role: (role = "default") => {
const VALID_ROLES = ["default", "admin", "manager"];
if (!VALID_ROLES.includes(role)) {
throw new Error(
`Invalid role. Allowed roles are: ${VALID_ROLES.join(", ")}`
);
}
return String(role);
},
dailyMessageLimit: (dailyMessageLimit = null) => {
if (dailyMessageLimit === null) return null;View on GitHub (pinned to 3aec848f28)