Mintplex-Labs/anything-llm · error

Invalid role. Allowed roles are

Error message

Invalid role. Allowed roles are: ${VALID_ROLES.join(", ")}

What it means

Thrown by the role validator when a create or update receives a role not in the hardcoded VALID_ROLES list ("default", "admin", "manager"). Roles are validated before any database write and the message interpolates the allowed list. Forks or version drift that add or rename roles will trip this when the client sends a value the running server does not know. Passing role: undefined is safe (defaults to "default"), but any other unknown string throws.

Solutions

  1. Use one of exactly: default, admin, manager
  2. Map human-readable labels to machine values before calling the API
  3. Derive the allowed list from the server contract rather than hardcoding it in clients
  4. If a custom role is truly required, extend VALID_ROLES in server/models/user.js and redeploy

Example fix

// before
await user.update(userId, { role: "Administrator" });

// after
await user.update(userId, { role: "admin" });
Defensive patterns

Strategy: validation

Validate before calling

const VALID_ROLES = ["default", "admin", "manager"];
function isValidRole(role) {
  return role == null || VALID_ROLES.includes(role);
}
if (!isValidRole(body.role)) {
  return res.status(400).json({ error: `Invalid role. Allowed roles are: ${VALID_ROLES.join(", ")}` });
}

Type guard

/** @param {unknown} v */
function isRole(v) {
  return typeof v === "string" && ["default", "admin", "manager"].includes(v);
}

Try / catch

try {
  await user.update(userId, { role });
} catch (e) {
  if (/Invalid role/i.test(e.message)) return res.status(400).json({ error: e.message });
  throw e;
}

Prevention

When it happens

Trigger: user.update(userId, { role: "owner" }) or User.create with role "superadmin"; an API client written against a fork with extra roles; sending a display label ("Administrator") instead of the machine value; role: "" from an empty form field.

Common situations: Version drift between the API client and server role list; custom forks adding roles then running upstream code; admin UI dropdown out of sync with backend; scripts promoting users with invented role names.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18). Data as JSON: /api/errors/4196e9fafd075fe6. Report an issue: GitHub.

Appendix: source

Thrown at server/models/user.js:54

      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;
      const limit = Number(dailyMessageLimit);
      if (isNaN(limit) || limit < 1) {
        throw new Error(
          "Daily message limit must be null or a number greater than or equal to 1"
        );
      }
      return limit;
    },
    bio: (bio = "") => {
      if (!bio || typeof bio !== "string") return "";
      if (bio.length > 1000)

View on GitHub (pinned to 3aec848f28)