{"record":{"id":"8f06770804b0ddb4","repo":"TencentCloud/TencentDB-Agent-Memory","slug":"permission-denied-8f0677","errorCode":"permission_denied","errorMessage":"user management requires system admin","messagePattern":"user management requires system admin","errorType":"error_code","errorClass":"MetadataError","httpStatus":null,"severity":"error","filePath":"MemoryCore/src/metadata/service/metadata-service.ts","lineNumber":517,"sourceCode":"    }\n    return toPublicUser(user, ctx);\n  }\n\n  async getUserById(userId: string): Promise<UserEntity | null> {\n    return this.store.getUserById(userId);\n  }\n\n  async getUserByKey(userKey: string): Promise<UserEntity | null> {\n    return this.store.getUserByKey(userKey);\n  }\n\n  async getUserByExternalId(authProvider: string, externalId: string): Promise<UserEntity | null> {\n    return this.store.getUserByExternalId(authProvider, externalId);\n  }\n\n  async deleteUsersForCaller(userIds: string[], ctx: V3AuthContext): Promise<BatchDeleteResult> {\n    if (!canManageUsers(ctx)) {\n      throw new MetadataError(\"permission_denied\", \"user management requires system admin\");\n    }\n    let deletingSystemAdmins = 0;\n    for (const id of userIds) {\n      const u = await this.getUserById(id);\n      if (u && isSystemAdminUser(u)) deletingSystemAdmins++;\n    }\n    const totalAdmins = await this.store.countSystemAdmins();\n    if (totalAdmins > 0 && totalAdmins - deletingSystemAdmins < 1) {\n      throw new MetadataError(\"last_system_admin\", \"cannot delete the last system_admin user\");\n    }\n    return this.deleteUsers(userIds);\n  }\n\n  async deleteUsers(userIds: string[]): Promise<BatchDeleteResult> {\n    return this.store.deleteUsers(userIds);\n  }\n\n  async listUsersForCaller(","sourceCodeStart":499,"sourceCodeEnd":535,"githubUrl":"https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/3efcd317b84146d6a08518ac0f7ee7c8a8d200ec/MemoryCore/src/metadata/service/metadata-service.ts#L499-L535","documentation":"MetadataError 'permission_denied' from deleteUsersForCaller: the supplied auth context fails canManageUsers, meaning only system admins may delete users. The check runs before any lookup or deletion, so the batch is rejected wholesale.","triggerScenarios":"Calling deleteUsersForCaller with a V3AuthContext whose role/type is not system admin (e.g. normal user token, missing admin claims).","commonSituations":"Calling an admin-only endpoint with a regular user's token; tokens minted without admin role after an auth-provider config change; stale tokens issued before a role promotion.","solutions":["Re-authenticate as (or obtain a token for) a system_admin user","Check the token/context carries admin role claims before calling; re-issue if role changed","Handle 'permission_denied' in the UI by hiding admin actions for non-admins"],"exampleFix":"// before\nawait svc.deleteUsersForCaller(ids, normalUserCtx); // throws\n// after\nif (canManageUsers(ctx)) {\n  await svc.deleteUsersForCaller(ids, ctx);\n}","handlingStrategy":"validation","validationCode":"if (!canManageUsers(ctx)) {\n  throw new Error('caller is not a system admin; refusing delete');\n}","typeGuard":"function isSystemAdminCtx(ctx: V3AuthContext): boolean {\n  return canManageUsers(ctx);\n}","tryCatchPattern":"try {\n  await svc.deleteUsersForCaller(ids, ctx);\n} catch (e) {\n  if (e instanceof MetadataError && e.code === 'permission_denied') {\n    // show 403-equivalent UI state\n  } else throw e;\n}","preventionTips":["Ensure admin tokens carry system admin role claims","Gate admin UI actions on the same permission check client-side","Re-authenticate after role changes so old non-admin tokens aren't reused"],"tags":["permission","authorization","admin"],"backgroundTag":"permission-denied","analyzedSha":"3efcd317b84146d6a08518ac0f7ee7c8a8d200ec","analyzedAt":"2026-09-01T05:44:22.276Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}