danny-avila/LibreChat · error · Error
Invalid principal ID: ${principalId}
Error message
Invalid principal ID: ${principalId} What it means
For USER and GROUP principals (anything that is not PUBLIC and not ROLE), grantPermission requires principalId to be a value that passes mongoose Types.ObjectId.isValid. The check fires when the id is missing or not a 24-hex-char ObjectId string.
Source
Thrown at packages/api/src/acl/accessControlService.ts:81
}
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 &&
(!principalId || !Types.ObjectId.isValid(principalId))
) {
// User and Group IDs must be valid ObjectIds
throw new Error(`Invalid principal ID: ${principalId}`);
}
if (!resourceId || !Types.ObjectId.isValid(resourceId)) {
throw new Error(`Invalid resource ID: ${resourceId}`);
}
this.validateResourceType(resourceType as ResourceType);
// Get the role to determine permission bits
const role = await this._dbMethods.findRoleByIdentifier(accessRoleId);
if (!role) {
throw new Error(`Role ${accessRoleId} not found`);
}
// Ensure the role is for the correct resource type
if (role.resourceType !== resourceType) {
throw new Error(
`Role ${accessRoleId} is for ${role.resourceType} resources, not ${resourceType}`,View on GitHub (pinned to 5ff282f900)
Solutions
- Pass the Mongo ObjectId of the user or group (typically req.user.userId or the group document's _id toString()).
- Validate the id format at the API boundary with Types.ObjectId.isValid before calling grantPermission.
- If your system uses non-ObjectId identifiers, map them to ObjectIds first.
Example fix
// before
await grantPermission({ principalType: PrincipalType.USER, principalId: req.user.email, ... });
// after
import { Types } from 'mongoose';
const userId = req.user.userId;
if (!Types.ObjectId.isValid(userId)) throw new Error('bad user id');
await grantPermission({ principalType: PrincipalType.USER, principalId: userId, ... }); Defensive patterns
Strategy: validation
Validate before calling
import { Types } from 'mongoose';
function assertObjectId(v: unknown): string {
if (typeof v !== 'string' || !Types.ObjectId.isValid(v)) {
throw new Error(`Invalid principal ID: ${String(v)}`);
}
return v;
} Type guard
import { Types } from 'mongoose';
const isObjectId = (v: unknown): v is string =>
typeof v === 'string' && Types.ObjectId.isValid(v); Prevention
- For USER/GROUP principals pass the Mongo _id.toString(), not username/email.
- Validate with Types.ObjectId.isValid at the API boundary.
When it happens
Trigger: grantPermission with principalType USER/GROUP and principalId that is undefined, a non-hex string, an email address, a username, or a malformed id from the client.
Common situations: Passing req.user.username or email instead of req.user.userId; a client sending a uuid/v4 instead of a Mongo ObjectId; string slicing that truncated the id.
Related errors
- Invalid resource ID: ${resourceId}
- Invalid principal ID: ${principalId}
- Invalid resourceType: ${resourceType}. Valid types: ${validT
- User principal not found
- Group principal not found
AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12).
Data as JSON: /api/errors/eef57abf443f6737.
Report an issue: GitHub.