From a804d6521027ce4c28df1ee93eb0ea4de71de752 Mon Sep 17 00:00:00 2001
From: neo773 <62795688+neo773@users.noreply.github.com>
Date: Wed, 6 Aug 2025 02:11:51 +0530
Subject: [PATCH] add userFriendly messages to PermissionsException (#13659)
/closes #13580
---
.../user/services/user.service.ts | 4 +++
.../workspace/services/workspace.service.ts | 8 ++++++
.../guards/settings-permissions.guard.ts | 4 +++
.../field-permission.service.ts | 28 +++++++++++++++++++
.../object-permission.service.ts | 28 +++++++++++++++++++
.../permission-flag.service.ts | 12 ++++++++
.../permissions/permissions.service.ts | 16 +++++++++++
.../metadata-modules/role/role.resolver.ts | 4 +++
.../metadata-modules/role/role.service.ts | 24 ++++++++++++++++
.../user-role/user-role.service.ts | 16 +++++++++++
.../workspace-datasource.service.ts | 4 +++
11 files changed, 148 insertions(+)
diff --git a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts
index bc4fe62cc4d..ccd390c9970 100644
--- a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts
+++ b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts
@@ -122,6 +122,10 @@ export class UserService extends TypeOrmQueryService {
throw new PermissionsException(
PermissionsExceptionMessage.CANNOT_DELETE_LAST_ADMIN_USER,
PermissionsExceptionCode.CANNOT_DELETE_LAST_ADMIN_USER,
+ {
+ userFriendlyMessage:
+ 'Cannot delete account: you are the only admin. Assign another admin or delete the workspace(s) first.',
+ },
);
}
throw error;
diff --git a/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts b/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts
index e32a7f6a303..1f4731b6fab 100644
--- a/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts
+++ b/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts
@@ -429,6 +429,10 @@ export class WorkspaceService extends TypeOrmQueryService {
throw new PermissionsException(
PermissionsExceptionMessage.PERMISSION_DENIED,
PermissionsExceptionCode.PERMISSION_DENIED,
+ {
+ userFriendlyMessage:
+ 'You do not have permission to manage security settings. Please contact your workspace administrator.',
+ },
);
}
}
@@ -475,6 +479,10 @@ export class WorkspaceService extends TypeOrmQueryService {
throw new PermissionsException(
PermissionsExceptionMessage.PERMISSION_DENIED,
PermissionsExceptionCode.PERMISSION_DENIED,
+ {
+ userFriendlyMessage:
+ 'You do not have permission to manage workspace settings. Please contact your workspace administrator.',
+ },
);
}
}
diff --git a/packages/twenty-server/src/engine/guards/settings-permissions.guard.ts b/packages/twenty-server/src/engine/guards/settings-permissions.guard.ts
index eb56ff3893e..5cc95182f9d 100644
--- a/packages/twenty-server/src/engine/guards/settings-permissions.guard.ts
+++ b/packages/twenty-server/src/engine/guards/settings-permissions.guard.ts
@@ -55,6 +55,10 @@ export const SettingsPermissionsGuard = (
throw new PermissionsException(
PermissionsExceptionMessage.PERMISSION_DENIED,
PermissionsExceptionCode.PERMISSION_DENIED,
+ {
+ userFriendlyMessage:
+ 'You do not have permission to access this feature. Please contact your workspace administrator for access.',
+ },
);
}
}
diff --git a/packages/twenty-server/src/engine/metadata-modules/object-permission/field-permission/field-permission.service.ts b/packages/twenty-server/src/engine/metadata-modules/object-permission/field-permission/field-permission.service.ts
index 4e9cc3f9ad2..80551f47af1 100644
--- a/packages/twenty-server/src/engine/metadata-modules/object-permission/field-permission/field-permission.service.ts
+++ b/packages/twenty-server/src/engine/metadata-modules/object-permission/field-permission/field-permission.service.ts
@@ -190,6 +190,10 @@ export class FieldPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.ONLY_FIELD_RESTRICTION_ALLOWED,
PermissionsExceptionCode.ONLY_FIELD_RESTRICTION_ALLOWED,
+ {
+ userFriendlyMessage:
+ 'Field permissions can only be used to restrict access, not to grant additional permissions.',
+ },
);
}
@@ -200,6 +204,10 @@ export class FieldPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.OBJECT_METADATA_NOT_FOUND,
PermissionsExceptionCode.OBJECT_METADATA_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'The object you are trying to set permissions for could not be found. It may have been deleted.',
+ },
);
}
@@ -207,6 +215,10 @@ export class FieldPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.CANNOT_ADD_FIELD_PERMISSION_ON_SYSTEM_OBJECT,
PermissionsExceptionCode.CANNOT_ADD_FIELD_PERMISSION_ON_SYSTEM_OBJECT,
+ {
+ userFriendlyMessage:
+ 'You cannot set field permissions on system objects as they are managed by the platform.',
+ },
);
}
@@ -219,6 +231,10 @@ export class FieldPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.FIELD_METADATA_NOT_FOUND,
PermissionsExceptionCode.FIELD_METADATA_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'The field you are trying to set permissions for could not be found. It may have been deleted.',
+ },
);
}
@@ -229,6 +245,10 @@ export class FieldPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.OBJECT_PERMISSION_NOT_FOUND,
PermissionsExceptionCode.OBJECT_PERMISSION_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'No permissions are set for this role on the selected object. Please set object permissions first.',
+ },
);
}
}
@@ -252,6 +272,10 @@ export class FieldPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.ROLE_NOT_FOUND,
PermissionsExceptionCode.ROLE_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'The role you are trying to modify could not be found. It may have been deleted or you may not have access to it.',
+ },
);
}
@@ -263,6 +287,10 @@ export class FieldPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.ROLE_NOT_EDITABLE,
PermissionsExceptionCode.ROLE_NOT_EDITABLE,
+ {
+ userFriendlyMessage:
+ 'This role cannot be modified because it is a system role. Only custom roles can be edited.',
+ },
);
}
}
diff --git a/packages/twenty-server/src/engine/metadata-modules/object-permission/object-permission.service.ts b/packages/twenty-server/src/engine/metadata-modules/object-permission/object-permission.service.ts
index 5691a4646bf..f27c99f6b46 100644
--- a/packages/twenty-server/src/engine/metadata-modules/object-permission/object-permission.service.ts
+++ b/packages/twenty-server/src/engine/metadata-modules/object-permission/object-permission.service.ts
@@ -65,6 +65,10 @@ export class ObjectPermissionService {
throw new PermissionsException(
'Object metadata id not found',
PermissionsExceptionCode.OBJECT_METADATA_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'The object you are trying to set permissions for could not be found. It may have been deleted.',
+ },
);
}
@@ -72,6 +76,10 @@ export class ObjectPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.CANNOT_ADD_OBJECT_PERMISSION_ON_SYSTEM_OBJECT,
PermissionsExceptionCode.CANNOT_ADD_OBJECT_PERMISSION_ON_SYSTEM_OBJECT,
+ {
+ userFriendlyMessage:
+ 'You cannot set permissions on system objects as they are managed by the platform.',
+ },
);
}
});
@@ -174,6 +182,10 @@ export class ObjectPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.CANNOT_GIVE_WRITING_PERMISSION_ON_NON_READABLE_OBJECT,
PermissionsExceptionCode.CANNOT_GIVE_WRITING_PERMISSION_ON_NON_READABLE_OBJECT,
+ {
+ userFriendlyMessage:
+ 'You cannot grant edit permissions without also granting read permissions. Please enable read access first.',
+ },
);
}
}
@@ -203,6 +215,10 @@ export class ObjectPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.ROLE_NOT_FOUND,
PermissionsExceptionCode.ROLE_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'The role you are trying to modify could not be found. It may have been deleted or you may not have access to it.',
+ },
);
}
@@ -217,6 +233,10 @@ export class ObjectPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.OBJECT_METADATA_NOT_FOUND,
PermissionsExceptionCode.OBJECT_METADATA_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'One or more objects you are trying to set permissions for could not be found. They may have been deleted.',
+ },
);
}
}
@@ -241,6 +261,10 @@ export class ObjectPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.ROLE_NOT_FOUND,
PermissionsExceptionCode.ROLE_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'The role you are trying to modify could not be found. It may have been deleted or you may not have access to it.',
+ },
);
}
@@ -252,6 +276,10 @@ export class ObjectPermissionService {
throw new PermissionsException(
PermissionsExceptionMessage.ROLE_NOT_EDITABLE,
PermissionsExceptionCode.ROLE_NOT_EDITABLE,
+ {
+ userFriendlyMessage:
+ 'This role cannot be modified because it is a system role. Only custom roles can be edited.',
+ },
);
}
}
diff --git a/packages/twenty-server/src/engine/metadata-modules/permission-flag/permission-flag.service.ts b/packages/twenty-server/src/engine/metadata-modules/permission-flag/permission-flag.service.ts
index 2acb01a5a46..4cac81c10cf 100644
--- a/packages/twenty-server/src/engine/metadata-modules/permission-flag/permission-flag.service.ts
+++ b/packages/twenty-server/src/engine/metadata-modules/permission-flag/permission-flag.service.ts
@@ -45,6 +45,10 @@ export class PermissionFlagService {
throw new PermissionsException(
`${PermissionsExceptionMessage.INVALID_SETTING}: ${invalidFlags.join(', ')}`,
PermissionsExceptionCode.INVALID_SETTING,
+ {
+ userFriendlyMessage:
+ 'Some of the permissions you selected are not valid. Please try again with valid permission settings.',
+ },
);
}
@@ -109,6 +113,10 @@ export class PermissionFlagService {
throw new PermissionsException(
PermissionsExceptionMessage.ROLE_NOT_FOUND,
PermissionsExceptionCode.ROLE_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'The role you are trying to modify could not be found. It may have been deleted or you may not have access to it.',
+ },
);
}
}
@@ -143,6 +151,10 @@ export class PermissionFlagService {
throw new PermissionsException(
PermissionsExceptionMessage.ROLE_NOT_EDITABLE,
PermissionsExceptionCode.ROLE_NOT_EDITABLE,
+ {
+ userFriendlyMessage:
+ 'This role cannot be modified because it is a system role. Only custom roles can be edited.',
+ },
);
}
}
diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts
index b1a735ed2a1..79d2bcf9259 100644
--- a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts
+++ b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts
@@ -53,6 +53,10 @@ export class PermissionsService {
throw new PermissionsException(
PermissionsExceptionMessage.NO_ROLE_FOUND_FOR_USER_WORKSPACE,
PermissionsExceptionCode.NO_ROLE_FOUND_FOR_USER_WORKSPACE,
+ {
+ userFriendlyMessage:
+ 'Your role in this workspace could not be found. Please contact your workspace administrator.',
+ },
);
}
@@ -162,6 +166,10 @@ export class PermissionsService {
throw new PermissionsException(
PermissionsExceptionMessage.API_KEY_ROLE_NOT_FOUND,
PermissionsExceptionCode.API_KEY_ROLE_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'The API key does not have a valid role assigned. Please check your API key configuration.',
+ },
);
}
@@ -180,6 +188,10 @@ export class PermissionsService {
throw new PermissionsException(
PermissionsExceptionMessage.NO_ROLE_FOUND_FOR_USER_WORKSPACE,
PermissionsExceptionCode.NO_ROLE_FOUND_FOR_USER_WORKSPACE,
+ {
+ userFriendlyMessage:
+ 'Your role in this workspace could not be found. Please contact your workspace administrator.',
+ },
);
}
@@ -189,6 +201,10 @@ export class PermissionsService {
throw new PermissionsException(
PermissionsExceptionMessage.NO_AUTHENTICATION_CONTEXT,
PermissionsExceptionCode.NO_AUTHENTICATION_CONTEXT,
+ {
+ userFriendlyMessage:
+ 'Authentication is required to access this feature. Please sign in and try again.',
+ },
);
}
diff --git a/packages/twenty-server/src/engine/metadata-modules/role/role.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/role/role.resolver.ts
index 688ecf6c5eb..23229e9c21e 100644
--- a/packages/twenty-server/src/engine/metadata-modules/role/role.resolver.ts
+++ b/packages/twenty-server/src/engine/metadata-modules/role/role.resolver.ts
@@ -85,6 +85,10 @@ export class RoleResolver {
throw new PermissionsException(
PermissionsExceptionMessage.CANNOT_UPDATE_SELF_ROLE,
PermissionsExceptionCode.CANNOT_UPDATE_SELF_ROLE,
+ {
+ userFriendlyMessage:
+ 'You cannot change your own role. Please ask another administrator to update your role.',
+ },
);
}
diff --git a/packages/twenty-server/src/engine/metadata-modules/role/role.service.ts b/packages/twenty-server/src/engine/metadata-modules/role/role.service.ts
index 5415d5f7160..7815ffda103 100644
--- a/packages/twenty-server/src/engine/metadata-modules/role/role.service.ts
+++ b/packages/twenty-server/src/engine/metadata-modules/role/role.service.ts
@@ -122,6 +122,10 @@ export class RoleService {
throw new PermissionsException(
PermissionsExceptionMessage.ROLE_NOT_FOUND,
PermissionsExceptionCode.ROLE_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'The role you are looking for could not be found. It may have been deleted or you may not have access to it.',
+ },
);
}
@@ -185,6 +189,10 @@ export class RoleService {
throw new PermissionsException(
PermissionsExceptionMessage.DEFAULT_ROLE_NOT_FOUND,
PermissionsExceptionCode.DEFAULT_ROLE_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'The default role for this workspace could not be found. Please contact support for assistance.',
+ },
);
}
@@ -283,6 +291,10 @@ export class RoleService {
throw new PermissionsException(
error.message,
PermissionsExceptionCode.INVALID_ARG,
+ {
+ userFriendlyMessage:
+ 'Some of the information provided is invalid. Please check your input and try again.',
+ },
);
}
}
@@ -346,6 +358,10 @@ export class RoleService {
throw new PermissionsException(
PermissionsExceptionMessage.CANNOT_GIVE_WRITING_PERMISSION_WITHOUT_READING_PERMISSION,
PermissionsExceptionCode.CANNOT_GIVE_WRITING_PERMISSION_WITHOUT_READING_PERMISSION,
+ {
+ userFriendlyMessage:
+ 'You cannot grant edit permissions without also granting read permissions. Please enable read access first.',
+ },
);
}
}
@@ -401,6 +417,10 @@ export class RoleService {
throw new PermissionsException(
PermissionsExceptionMessage.ROLE_NOT_EDITABLE,
PermissionsExceptionCode.ROLE_NOT_EDITABLE,
+ {
+ userFriendlyMessage:
+ 'This role cannot be modified because it is a system role. Only custom roles can be edited.',
+ },
);
}
}
@@ -416,6 +436,10 @@ export class RoleService {
throw new PermissionsException(
PermissionsExceptionMessage.DEFAULT_ROLE_CANNOT_BE_DELETED,
PermissionsExceptionCode.DEFAULT_ROLE_CANNOT_BE_DELETED,
+ {
+ userFriendlyMessage:
+ 'The default role cannot be deleted as it is required for the workspace to function properly.',
+ },
);
}
}
diff --git a/packages/twenty-server/src/engine/metadata-modules/user-role/user-role.service.ts b/packages/twenty-server/src/engine/metadata-modules/user-role/user-role.service.ts
index 7d9459d01c2..5c7fef2421c 100644
--- a/packages/twenty-server/src/engine/metadata-modules/user-role/user-role.service.ts
+++ b/packages/twenty-server/src/engine/metadata-modules/user-role/user-role.service.ts
@@ -195,6 +195,10 @@ export class UserRoleService {
throw new PermissionsException(
PermissionsExceptionMessage.NO_ROLE_FOUND_FOR_USER_WORKSPACE,
PermissionsExceptionCode.NO_ROLE_FOUND_FOR_USER_WORKSPACE,
+ {
+ userFriendlyMessage:
+ 'Your role in this workspace could not be found. Please contact your workspace administrator.',
+ },
);
}
@@ -227,6 +231,10 @@ export class UserRoleService {
throw new PermissionsException(
'User workspace not found',
PermissionsExceptionCode.USER_WORKSPACE_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'Your workspace membership could not be found. You may no longer have access to this workspace.',
+ },
);
}
@@ -240,6 +248,10 @@ export class UserRoleService {
throw new PermissionsException(
'Role not found',
PermissionsExceptionCode.ROLE_NOT_FOUND,
+ {
+ userFriendlyMessage:
+ 'The role you are trying to assign could not be found. It may have been deleted.',
+ },
);
}
@@ -280,6 +292,10 @@ export class UserRoleService {
throw new PermissionsException(
PermissionsExceptionMessage.CANNOT_UNASSIGN_LAST_ADMIN,
PermissionsExceptionCode.CANNOT_UNASSIGN_LAST_ADMIN,
+ {
+ userFriendlyMessage:
+ 'You cannot remove the admin role from the last administrator. Please assign another administrator first.',
+ },
);
}
}
diff --git a/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts b/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts
index eae885d932e..628fb04c8cf 100644
--- a/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts
+++ b/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts
@@ -80,6 +80,10 @@ export class WorkspaceDataSourceService {
throw new PermissionsException(
'Method not allowed as permissions are not handled at datasource level.',
PermissionsExceptionCode.METHOD_NOT_ALLOWED,
+ {
+ userFriendlyMessage:
+ 'This operation is not allowed. Please try a different approach or contact support if you need assistance.',
+ },
);
}
}