{"record":{"id":"4196e9fafd075fe6","repo":"Mintplex-Labs/anything-llm","slug":"invalid-role-allowed-roles-are-valid-roles-joi","errorCode":null,"errorMessage":"Invalid role. Allowed roles are: ${VALID_ROLES.join(\", \")}","messagePattern":"Invalid role\\. Allowed roles are: (.+?)","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"server/models/user.js","lineNumber":54,"sourceCode":"      try {\n        const username = String(newValue);\n        if (username.length > 64)\n          throw new Error(\"Username cannot be longer than 64 characters\");\n        if (username.length < 2)\n          throw new Error(\"Username must be at least 2 characters\");\n        if (!User.usernameRegex.test(username))\n          throw new Error(\n            \"Username must start with a lowercase letter and only contain lowercase letters, numbers, underscores, hyphens, and periods\"\n          );\n        return username;\n      } catch (e) {\n        throw new Error(e.message);\n      }\n    },\n    role: (role = \"default\") => {\n      const VALID_ROLES = [\"default\", \"admin\", \"manager\"];\n      if (!VALID_ROLES.includes(role)) {\n        throw new Error(\n          `Invalid role. Allowed roles are: ${VALID_ROLES.join(\", \")}`\n        );\n      }\n      return String(role);\n    },\n    dailyMessageLimit: (dailyMessageLimit = null) => {\n      if (dailyMessageLimit === null) return null;\n      const limit = Number(dailyMessageLimit);\n      if (isNaN(limit) || limit < 1) {\n        throw new Error(\n          \"Daily message limit must be null or a number greater than or equal to 1\"\n        );\n      }\n      return limit;\n    },\n    bio: (bio = \"\") => {\n      if (!bio || typeof bio !== \"string\") return \"\";\n      if (bio.length > 1000)","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/models/user.js#L36-L72","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use one of exactly: default, admin, manager","Map human-readable labels to machine values before calling the API","Derive the allowed list from the server contract rather than hardcoding it in clients","If a custom role is truly required, extend VALID_ROLES in server/models/user.js and redeploy"],"exampleFix":"// before\nawait user.update(userId, { role: \"Administrator\" });\n\n// after\nawait user.update(userId, { role: \"admin\" });","handlingStrategy":"validation","validationCode":"const VALID_ROLES = [\"default\", \"admin\", \"manager\"];\nfunction isValidRole(role) {\n  return role == null || VALID_ROLES.includes(role);\n}\nif (!isValidRole(body.role)) {\n  return res.status(400).json({ error: `Invalid role. Allowed roles are: ${VALID_ROLES.join(\", \")}` });\n}","typeGuard":"/** @param {unknown} v */\nfunction isRole(v) {\n  return typeof v === \"string\" && [\"default\", \"admin\", \"manager\"].includes(v);\n}","tryCatchPattern":"try {\n  await user.update(userId, { role });\n} catch (e) {\n  if (/Invalid role/i.test(e.message)) return res.status(400).json({ error: e.message });\n  throw e;\n}","preventionTips":["Treat the role list as a versioned API contract; never hardcode in clients","Send machine values, never display labels","Guard scripts with an includes() check before promoting users"],"tags":["validation","role","enum","user-management"],"backgroundTag":"invalid-enum-value","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}