danny-avila/LibreChat · error · Error
Invalid principal type
Error message
Invalid principal type: ${principalType} What it means
grantPermission() in PermissionService.js:77 throws this as its first guard when principalType is not a value of the PrincipalType enum (user, group, public, role). It prevents persisting ACL records with an unknown principal category, which would be silently invisible to every authorization check.
Solutions
- Pass principalType as one of PrincipalType.USER, .GROUP, .PUBLIC, or .ROLE.
- Type the parameter as PrincipalType in TypeScript so the compiler rejects invalid values.
- If you genuinely need a new principal category, extend the PrincipalType enum and the ACL schema first.
Example fix
// before
grantPermission({ principalType: 'team', ... });
// after
import { PrincipalType } from 'librechat-data-provider';
grantPermission({ principalType: PrincipalType.GROUP, ... }); Defensive patterns
Strategy: type-guard
Validate before calling
const VALID_PRINCIPAL_TYPES = new Set(Object.values(PrincipalType));
function assertPrincipalType(t) {
if (!VALID_PRINCIPAL_TYPES.has(t)) throw new Error(`unsupported principalType: ${t}`);
} Type guard
const isPrincipalType = (t) => Object.values(PrincipalType).includes(t);
Prevention
- Type the parameter as PrincipalType in TS so invalid values fail to compile.
- Drive the principalType dropdown in the UI directly from the enum values.
When it happens
Trigger: A caller passes a principalType not equal to 'user'|'group'|'public'|'role' — e.g. 'team', 'org', an integer, or undefined. Reached before the principalId/resourceId checks, so any malformed principalType surfaces here first.
Common situations: Frontend introduced a new share target type without backend enum support. A serialization bug converts the enum value to its index. A refactored call site forgets to pass principalType at all (undefined).
Related errors
- Invalid resourceType
- Group principal not found
- Invalid principal ID
- Invalid principal ID
- Invalid principal type
AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12).
Data as JSON: /api/errors/ed23a8187437e5d0.
Report an issue: GitHub.
Appendix: source
Thrown at api/server/services/PermissionService.js:77
* @param {string} params.resourceType - Type of resource (e.g., 'agent')
* @param {string|mongoose.Types.ObjectId} params.resourceId - The ID of the resource
* @param {string} params.accessRoleId - The ID of the role (e.g., AccessRoleIds.AGENT_VIEWER, AccessRoleIds.AGENT_EDITOR)
* @param {string|mongoose.Types.ObjectId} params.grantedBy - User ID granting the permission
* @param {mongoose.ClientSession} [params.session] - Optional MongoDB session for transactions
* @returns {Promise<Object>} The created or updated ACL entry
*/
const grantPermission = async ({
principalType,
principalId,
resourceType,
resourceId,
accessRoleId,
grantedBy,
session,
}) => {
try {
if (!Object.values(PrincipalType).includes(principalType)) {
throw new Error(`Invalid principal type: ${principalType}`);
}
if (principalType !== PrincipalType.PUBLIC && !principalId) {
throw new Error('Principal ID is required for user, group, and role principals');
}
// Validate principalId based on type
if (principalId && principalType === PrincipalType.ROLE) {
// Role IDs are strings (role names)
if (typeof principalId !== 'string' || principalId.trim().length === 0) {
throw new Error(`Invalid role ID: ${principalId}`);
}
} else if (
principalType &&
principalType !== PrincipalType.PUBLIC &&
!mongoose.Types.ObjectId.isValid(principalId)
) {
// User and Group IDs must be valid ObjectIdsView on GitHub (pinned to 5ff282f900)