danny-avila/LibreChat · error · Error

Invalid resource ID: ${resourceId}

Error message

Invalid resource ID: ${resourceId}

What it means

grantPermission requires resourceId to be present and a valid Mongo ObjectId (Types.ObjectId.isValid). This is checked for every grant regardless of principal type, since every ACL entry must anchor to a real resource document.

Source

Thrown at packages/api/src/acl/accessControlService.ts:85

      }

      // 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}`,
        );
      }
      return await this._dbMethods.grantPermission(
        principalType,

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Resolve the resource's _id from the database and pass its toString().
  2. Validate resourceId with Types.ObjectId.isValid at the route handler and return 400 on failure.
  3. Ensure the resource still exists before granting permissions on it.

Example fix

// before
await grantPermission({ ..., resourceId: agentSlug });

// after
import { Types } from 'mongoose';
if (!Types.ObjectId.isValid(agentSlug)) {
  return res.status(400).json({ error: 'Invalid resource id' });
}
await grantPermission({ ..., resourceId: agentSlug });
Defensive patterns

Strategy: validation

Validate before calling

import { Types } from 'mongoose';
function assertResourceId(v: unknown): string {
  if (typeof v !== 'string' || !Types.ObjectId.isValid(v)) {
    throw new Error(`Invalid resource ID: ${String(v)}`);
  }
  return v;
}

Type guard

import { Types } from 'mongoose';
const isResourceId = (v: unknown): v is string =>
  typeof v === 'string' && Types.ObjectId.isValid(v);

Prevention

When it happens

Trigger: grantPermission with resourceId undefined, null, an empty string, a slug, or any non-24-hex-char value; passing the resource's name or path instead of its _id.

Common situations: Client sends a resource slug or index instead of its Mongo id; a route parameter parsed incorrectly; the resource was deleted between fetch and grant so its id reference is stale.

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/cd1acb211aefa556. Report an issue: GitHub.