From c13bc60dad448606885053effc04ec347933a68a Mon Sep 17 00:00:00 2001 From: Marie <51697796+ijreilly@users.noreply.github.com> Date: Wed, 9 Jul 2025 17:13:44 +0200 Subject: [PATCH] Improve error handling (#13130) In the BE we throw custom errors with precise error codes (e.g. "LABEL_ALREADY_EXISTS") before catching them in filters and rethrowing BaseGraphQLErrors (standard errors such as NotFoundError, UserInputError etc.). In the FE we were grouping sentries based on the error codes but we were actually grouping by very broad codes such as "NOT_FOUND" or "BAD_USER_INPUT", extracted from the BaseGraphQLErrors. To fix that, we update the BaseGraphQLError constructor api to allow to pass on the CustomError directly and retrieve from it the original code and store it in existing property `subCode` that we will use in the FE to send errors to sentry. This new api also eases usage of `userFriendlyMessage` that is passed on to the api response and therefore to the FE when CustomError is passed on directly to the BaseGraphQLError constructor. --- .../modules/apollo/services/apollo.factory.ts | 4 +- ...hql-query-runner-exception-handler.util.ts | 4 +- .../utils/workspace-exception-handler.util.ts | 8 +- ...approved-access-domain-exception-filter.ts | 4 +- .../audit/audit-exception-filter.ts | 2 +- .../auth-graphql-api-exception.filter.ts | 16 +- ...mail-verification-exception-filter.util.ts | 12 +- .../graphql/utils/graphql-errors.util.ts | 163 +++++++++++++----- ...rmer-graphql-api-exception-handler.util.ts | 4 +- ...ow-trigger-graphql-api-exception.filter.ts | 8 +- ...pace-graphql-api-exception-handler.util.ts | 6 +- ...data-graphql-api-exception-handler.util.ts | 16 +- ...data-graphql-api-exception-handler.util.ts | 14 +- .../permissions/permissions.exception.ts | 8 +- ...sion-graphql-api-exception-handler.util.ts | 13 +- .../metadata-modules/role/role.service.ts | 2 + ...ion-graphql-api-exception-handler.utils.ts | 6 +- ...a-relation-update.integration-spec.ts.snap | 2 + ...ta-related-record.integration-spec.ts.snap | 2 + ...eld-metadata-enum.integration-spec.ts.snap | 68 ++++++++ ...um-field-metadata.integration-spec.ts.snap | 66 +++++++ ...ld-metadata-phone.integration-spec.ts.snap | 14 ++ 22 files changed, 319 insertions(+), 123 deletions(-) diff --git a/packages/twenty-front/src/modules/apollo/services/apollo.factory.ts b/packages/twenty-front/src/modules/apollo/services/apollo.factory.ts index 9266ef5ff..28c291b48 100644 --- a/packages/twenty-front/src/modules/apollo/services/apollo.factory.ts +++ b/packages/twenty-front/src/modules/apollo/services/apollo.factory.ts @@ -183,9 +183,9 @@ export class ApolloFactory implements ApolloManager { const fingerPrint: string[] = []; if (isDefined(graphQLError.extensions)) { scope.setExtra('extensions', graphQLError.extensions); - if (isDefined(graphQLError.extensions.code)) { + if (isDefined(graphQLError.extensions.subCode)) { fingerPrint.push( - graphQLError.extensions.code as string, + graphQLError.extensions.subCode as string, ); } } diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/graphql-query-runner-exception-handler.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/graphql-query-runner-exception-handler.util.ts index 70486a6df..8ca229493 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/graphql-query-runner-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/graphql-query-runner-exception-handler.util.ts @@ -22,9 +22,9 @@ export const graphqlQueryRunnerExceptionHandler = ( case GraphqlQueryRunnerExceptionCode.FIELD_NOT_FOUND: case GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT: case GraphqlQueryRunnerExceptionCode.NOT_IMPLEMENTED: - throw new UserInputError(error.message); + throw new UserInputError(error); case GraphqlQueryRunnerExceptionCode.RECORD_NOT_FOUND: - throw new NotFoundError(error.message); + throw new NotFoundError(error); case GraphqlQueryRunnerExceptionCode.RELATION_SETTINGS_NOT_FOUND: case GraphqlQueryRunnerExceptionCode.RELATION_TARGET_OBJECT_METADATA_NOT_FOUND: case GraphqlQueryRunnerExceptionCode.INVALID_POST_HOOK_PAYLOAD: diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/workspace-exception-handler.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/workspace-exception-handler.util.ts index 04eab266f..2f44cc8b1 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/workspace-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/utils/workspace-exception-handler.util.ts @@ -14,16 +14,16 @@ export const workspaceExceptionHandler = ( ) => { switch (error.code) { case WorkspaceQueryRunnerExceptionCode.DATA_NOT_FOUND: - throw new NotFoundError(error.message); + throw new NotFoundError(error); case WorkspaceQueryRunnerExceptionCode.INVALID_QUERY_INPUT: - throw new UserInputError(error.message); + throw new UserInputError(error); case WorkspaceQueryRunnerExceptionCode.QUERY_VIOLATES_UNIQUE_CONSTRAINT: case WorkspaceQueryRunnerExceptionCode.QUERY_VIOLATES_FOREIGN_KEY_CONSTRAINT: case WorkspaceQueryRunnerExceptionCode.TOO_MANY_ROWS_AFFECTED: case WorkspaceQueryRunnerExceptionCode.NO_ROWS_AFFECTED: - throw new ForbiddenError(error.message); + throw new ForbiddenError(error); case WorkspaceQueryRunnerExceptionCode.QUERY_TIMEOUT: - throw new TimeoutError(error.message); + throw new TimeoutError(error); case WorkspaceQueryRunnerExceptionCode.INTERNAL_SERVER_ERROR: throw error; default: { diff --git a/packages/twenty-server/src/engine/core-modules/approved-access-domain/approved-access-domain-exception-filter.ts b/packages/twenty-server/src/engine/core-modules/approved-access-domain/approved-access-domain-exception-filter.ts index b01aea5f4..5a3bf0b8b 100644 --- a/packages/twenty-server/src/engine/core-modules/approved-access-domain/approved-access-domain-exception-filter.ts +++ b/packages/twenty-server/src/engine/core-modules/approved-access-domain/approved-access-domain-exception-filter.ts @@ -17,9 +17,7 @@ export class ApprovedAccessDomainExceptionFilter implements ExceptionFilter { case ApprovedAccessDomainExceptionCode.APPROVED_ACCESS_DOMAIN_VALIDATION_TOKEN_INVALID: case ApprovedAccessDomainExceptionCode.APPROVED_ACCESS_DOMAIN_ALREADY_VALIDATED: case ApprovedAccessDomainExceptionCode.APPROVED_ACCESS_DOMAIN_MUST_BE_A_COMPANY_DOMAIN: - throw new ForbiddenError(exception.message, { - userFriendlyMessage: exception.userFriendlyMessage, - }); + throw new ForbiddenError(exception); default: { const _exhaustiveCheck: never = exception.code; diff --git a/packages/twenty-server/src/engine/core-modules/audit/audit-exception-filter.ts b/packages/twenty-server/src/engine/core-modules/audit/audit-exception-filter.ts index af8d32731..f590acd50 100644 --- a/packages/twenty-server/src/engine/core-modules/audit/audit-exception-filter.ts +++ b/packages/twenty-server/src/engine/core-modules/audit/audit-exception-filter.ts @@ -12,7 +12,7 @@ export class AuditExceptionFilter implements ExceptionFilter { switch (exception.code) { case AuditExceptionCode.INVALID_TYPE: case AuditExceptionCode.INVALID_INPUT: - throw new UserInputError(exception.message); + throw new UserInputError(exception); default: { const _exhaustiveCheck: never = exception.code; diff --git a/packages/twenty-server/src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter.ts b/packages/twenty-server/src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter.ts index 6cba07824..5e0b407ce 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter.ts @@ -18,13 +18,9 @@ export class AuthGraphqlApiExceptionFilter implements ExceptionFilter { catch(exception: AuthException) { switch (exception.code) { case AuthExceptionCode.CLIENT_NOT_FOUND: - throw new NotFoundError(exception.message, { - userFriendlyMessage: exception.userFriendlyMessage, - }); + throw new NotFoundError(exception); case AuthExceptionCode.INVALID_INPUT: - throw new UserInputError(exception.message, { - userFriendlyMessage: exception.userFriendlyMessage, - }); + throw new UserInputError(exception); case AuthExceptionCode.FORBIDDEN_EXCEPTION: case AuthExceptionCode.INSUFFICIENT_SCOPES: case AuthExceptionCode.OAUTH_ACCESS_DENIED: @@ -33,13 +29,12 @@ export class AuthGraphqlApiExceptionFilter implements ExceptionFilter { case AuthExceptionCode.SIGNUP_DISABLED: case AuthExceptionCode.MISSING_ENVIRONMENT_VARIABLE: case AuthExceptionCode.INVALID_JWT_TOKEN_TYPE: - throw new ForbiddenError(exception.message, { - userFriendlyMessage: exception.userFriendlyMessage, - }); + throw new ForbiddenError(exception); case AuthExceptionCode.GOOGLE_API_AUTH_DISABLED: case AuthExceptionCode.MICROSOFT_API_AUTH_DISABLED: throw new ForbiddenError(exception.message, { userFriendlyMessage: t`Authentication is not enabled with this provider.`, + subCode: exception.code, }); case AuthExceptionCode.EMAIL_NOT_VERIFIED: case AuthExceptionCode.INVALID_DATA: @@ -50,10 +45,11 @@ export class AuthGraphqlApiExceptionFilter implements ExceptionFilter { case AuthExceptionCode.UNAUTHENTICATED: throw new AuthenticationError(exception.message, { userFriendlyMessage: t`You must be authenticated to perform this action.`, + subCode: exception.code, }); case AuthExceptionCode.USER_NOT_FOUND: case AuthExceptionCode.WORKSPACE_NOT_FOUND: - throw new AuthenticationError(exception.message); + throw new AuthenticationError(exception); case AuthExceptionCode.INTERNAL_SERVER_ERROR: case AuthExceptionCode.USER_WORKSPACE_NOT_FOUND: throw exception; diff --git a/packages/twenty-server/src/engine/core-modules/email-verification/email-verification-exception-filter.util.ts b/packages/twenty-server/src/engine/core-modules/email-verification/email-verification-exception-filter.util.ts index 09a703ab9..f485f4706 100644 --- a/packages/twenty-server/src/engine/core-modules/email-verification/email-verification-exception-filter.util.ts +++ b/packages/twenty-server/src/engine/core-modules/email-verification/email-verification-exception-filter.util.ts @@ -23,13 +23,9 @@ export class EmailVerificationExceptionFilter implements ExceptionFilter { case EmailVerificationExceptionCode.INVALID_TOKEN: case EmailVerificationExceptionCode.INVALID_APP_TOKEN_TYPE: case EmailVerificationExceptionCode.RATE_LIMIT_EXCEEDED: - throw new ForbiddenError(exception.message, { - subCode: exception.code, - }); + throw new ForbiddenError(exception); case EmailVerificationExceptionCode.EMAIL_MISSING: - throw new UserInputError(exception.message, { - subCode: exception.code, - }); + throw new UserInputError(exception); case EmailVerificationExceptionCode.EMAIL_ALREADY_VERIFIED: throw new UserInputError(exception.message, { subCode: exception.code, @@ -41,9 +37,7 @@ export class EmailVerificationExceptionFilter implements ExceptionFilter { userFriendlyMessage: t`Email verification not required.`, }); case EmailVerificationExceptionCode.INVALID_EMAIL: - throw new UserInputError(exception.message, { - subCode: exception.code, - }); + throw new UserInputError(exception); default: { const _exhaustiveCheck: never = exception.code; diff --git a/packages/twenty-server/src/engine/core-modules/graphql/utils/graphql-errors.util.ts b/packages/twenty-server/src/engine/core-modules/graphql/utils/graphql-errors.util.ts index f5adccadf..1b67fe2aa 100644 --- a/packages/twenty-server/src/engine/core-modules/graphql/utils/graphql-errors.util.ts +++ b/packages/twenty-server/src/engine/core-modules/graphql/utils/graphql-errors.util.ts @@ -6,6 +6,8 @@ import { SourceLocation, } from 'graphql'; +import { CustomException } from 'src/utils/custom-exception'; + declare module 'graphql' { export interface GraphQLErrorExtensions { exception?: { @@ -48,29 +50,42 @@ export class BaseGraphQLError extends GraphQLError { // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; - constructor( - message: string, + exceptionOrMessage: string | CustomException, code?: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any extensions?: Record, ) { - super(message); + if (exceptionOrMessage instanceof CustomException) { + const exception = exceptionOrMessage; + + super(exception.message); + + this.extensions = { + subCode: exception.code, + userFriendlyMessage: exception.userFriendlyMessage, + code, + }; + } else { + const message = exceptionOrMessage; + + super(message); + + if (extensions?.extensions) { + throw new Error( + 'Pass extensions directly as the third argument of the ApolloError constructor: `new ' + + 'ApolloError(message, code, {myExt: value})`, not `new ApolloError(message, code, ' + + '{extensions: {myExt: value}})`', + ); + } + + this.extensions = { ...extensions, code }; + } // if no name provided, use the default. defineProperty ensures that it stays non-enumerable if (!this.name) { Object.defineProperty(this, 'name', { value: 'GraphQLError' }); } - - if (extensions?.extensions) { - throw new Error( - 'Pass extensions directly as the third argument of the ApolloError constructor: `new ' + - 'ApolloError(message, code, {myExt: value})`, not `new ApolloError(message, code, ' + - '{extensions: {myExt: value}})`', - ); - } - - this.extensions = { ...extensions, code }; } toJSON(): GraphQLFormattedError { @@ -113,28 +128,62 @@ export class ValidationError extends BaseGraphQLError { } } -export class AuthenticationError extends BaseGraphQLError { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions) { - super(message, ErrorCode.UNAUTHENTICATED, extensions); +export class NotFoundError extends BaseGraphQLError { + constructor(exception: CustomException); + constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions); + + constructor( + messageOrException: string | CustomException, + extensions?: RestrictedGraphQLErrorExtensions, + ) { + super(messageOrException, ErrorCode.NOT_FOUND, extensions); + Object.defineProperty(this, 'name', { value: 'NotFoundError' }); + } +} + +export class AuthenticationError extends BaseGraphQLError { + constructor(exception: CustomException); + + constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions); + + constructor( + messageOrException: string | CustomException, + extensions?: RestrictedGraphQLErrorExtensions, + ) { + super(messageOrException, ErrorCode.UNAUTHENTICATED, extensions); Object.defineProperty(this, 'name', { value: 'AuthenticationError' }); } } export class ForbiddenError extends BaseGraphQLError { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions) { - super(message, ErrorCode.FORBIDDEN, extensions); + constructor(exception: CustomException); + constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions); + + constructor( + messageOrException: string | CustomException, + extensions?: RestrictedGraphQLErrorExtensions, + ) { + super(messageOrException, ErrorCode.FORBIDDEN, extensions); Object.defineProperty(this, 'name', { value: 'ForbiddenError' }); } } export class PersistedQueryNotFoundError extends BaseGraphQLError { - constructor() { - super('PersistedQueryNotFound', ErrorCode.PERSISTED_QUERY_NOT_FOUND); + constructor(customException: CustomException); + constructor(message?: string, extensions?: RestrictedGraphQLErrorExtensions); + + constructor( + messageOrException?: string | CustomException, + extensions?: RestrictedGraphQLErrorExtensions, + ) { + super( + messageOrException || 'PersistedQueryNotFound', + ErrorCode.PERSISTED_QUERY_NOT_FOUND, + extensions, + ); Object.defineProperty(this, 'name', { value: 'PersistedQueryNotFoundError', }); @@ -142,12 +191,15 @@ export class PersistedQueryNotFoundError extends BaseGraphQLError { } export class PersistedQueryNotSupportedError extends BaseGraphQLError { - constructor() { + constructor( + messageOrException?: string | CustomException, + extensions?: RestrictedGraphQLErrorExtensions, + ) { super( - 'PersistedQueryNotSupported', + messageOrException || 'PersistedQueryNotSupported', ErrorCode.PERSISTED_QUERY_NOT_SUPPORTED, + extensions, ); - Object.defineProperty(this, 'name', { value: 'PersistedQueryNotSupportedError', }); @@ -155,52 +207,71 @@ export class PersistedQueryNotSupportedError extends BaseGraphQLError { } export class UserInputError extends BaseGraphQLError { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions) { - super(message, ErrorCode.BAD_USER_INPUT, extensions); + constructor(exception: CustomException); + constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions); + + constructor( + messageOrException: string | CustomException, + extensions?: RestrictedGraphQLErrorExtensions, + ) { + super(messageOrException, ErrorCode.BAD_USER_INPUT, extensions); Object.defineProperty(this, 'name', { value: 'UserInputError' }); } } -export class NotFoundError extends BaseGraphQLError { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions) { - super(message, ErrorCode.NOT_FOUND, extensions); - - Object.defineProperty(this, 'name', { value: 'NotFoundError' }); - } -} - export class MethodNotAllowedError extends BaseGraphQLError { - constructor(message: string) { - super(message, ErrorCode.METHOD_NOT_ALLOWED); + constructor(exception: CustomException); + constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions); + + constructor( + messageOrException: string | CustomException, + extensions?: RestrictedGraphQLErrorExtensions, + ) { + super(messageOrException, ErrorCode.METHOD_NOT_ALLOWED, extensions); Object.defineProperty(this, 'name', { value: 'MethodNotAllowedError' }); } } export class ConflictError extends BaseGraphQLError { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions) { - super(message, ErrorCode.CONFLICT, extensions); + constructor(exception: CustomException); + constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions); + + constructor( + messageOrException: string | CustomException, + extensions?: RestrictedGraphQLErrorExtensions, + ) { + super(messageOrException, ErrorCode.CONFLICT, extensions); Object.defineProperty(this, 'name', { value: 'ConflictError' }); } } export class TimeoutError extends BaseGraphQLError { - constructor(message: string) { - super(message, ErrorCode.TIMEOUT); + constructor(exception: CustomException); + constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions); + + constructor( + messageOrException: string | CustomException, + extensions?: RestrictedGraphQLErrorExtensions, + ) { + super(messageOrException, ErrorCode.TIMEOUT, extensions); Object.defineProperty(this, 'name', { value: 'TimeoutError' }); } } export class InternalServerError extends BaseGraphQLError { - constructor(message: string) { - super(message, ErrorCode.INTERNAL_SERVER_ERROR); + constructor(exception: CustomException); + constructor(message: string, extensions?: RestrictedGraphQLErrorExtensions); + + constructor( + messageOrException: string | CustomException, + extensions?: RestrictedGraphQLErrorExtensions, + ) { + super(messageOrException, ErrorCode.INTERNAL_SERVER_ERROR, extensions); Object.defineProperty(this, 'name', { value: 'InternalServerError' }); } } diff --git a/packages/twenty-server/src/engine/core-modules/record-transformer/utils/record-transformer-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/core-modules/record-transformer/utils/record-transformer-graphql-api-exception-handler.util.ts index 4597f0b0d..976e6dc4d 100644 --- a/packages/twenty-server/src/engine/core-modules/record-transformer/utils/record-transformer-graphql-api-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/core-modules/record-transformer/utils/record-transformer-graphql-api-exception-handler.util.ts @@ -17,9 +17,7 @@ export const recordTransformerGraphqlApiExceptionHandler = ( case RecordTransformerExceptionCode.CONFLICTING_PHONE_CALLING_CODE_AND_COUNTRY_CODE: case RecordTransformerExceptionCode.INVALID_PHONE_CALLING_CODE: case RecordTransformerExceptionCode.INVALID_URL: - throw new UserInputError(error.message, { - userFriendlyMessage: error.userFriendlyMessage, - }); + throw new UserInputError(error); default: { assertUnreachable(error.code); } diff --git a/packages/twenty-server/src/engine/core-modules/workflow/filters/workflow-trigger-graphql-api-exception.filter.ts b/packages/twenty-server/src/engine/core-modules/workflow/filters/workflow-trigger-graphql-api-exception.filter.ts index 29fff2dca..5cf6a7e6d 100644 --- a/packages/twenty-server/src/engine/core-modules/workflow/filters/workflow-trigger-graphql-api-exception.filter.ts +++ b/packages/twenty-server/src/engine/core-modules/workflow/filters/workflow-trigger-graphql-api-exception.filter.ts @@ -19,13 +19,9 @@ export const handleWorkflowTriggerException = ( case WorkflowTriggerExceptionCode.INVALID_WORKFLOW_TRIGGER: case WorkflowTriggerExceptionCode.INVALID_WORKFLOW_STATUS: case WorkflowTriggerExceptionCode.FORBIDDEN: - throw new UserInputError(exception.message, { - userFriendlyMessage: exception.userFriendlyMessage, - }); + throw new UserInputError(exception); case WorkflowTriggerExceptionCode.NOT_FOUND: - throw new NotFoundError(exception.message, { - userFriendlyMessage: exception.userFriendlyMessage, - }); + throw new NotFoundError(exception); case WorkflowTriggerExceptionCode.INTERNAL_ERROR: throw exception; default: { diff --git a/packages/twenty-server/src/engine/core-modules/workspace/utils/workspace-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/core-modules/workspace/utils/workspace-graphql-api-exception-handler.util.ts index 2f424dfdf..6d3ef80e3 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/utils/workspace-graphql-api-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/utils/workspace-graphql-api-exception-handler.util.ts @@ -13,13 +13,13 @@ export const workspaceGraphqlApiExceptionHandler = (error: Error) => { switch (error.code) { case WorkspaceExceptionCode.SUBDOMAIN_NOT_FOUND: case WorkspaceExceptionCode.WORKSPACE_NOT_FOUND: - throw new NotFoundError(error.message); + throw new NotFoundError(error); case WorkspaceExceptionCode.DOMAIN_ALREADY_TAKEN: case WorkspaceExceptionCode.SUBDOMAIN_ALREADY_TAKEN: - throw new ConflictError(error.message); + throw new ConflictError(error); case WorkspaceExceptionCode.ENVIRONMENT_VAR_NOT_ENABLED: case WorkspaceExceptionCode.WORKSPACE_CUSTOM_DOMAIN_DISABLED: - throw new ForbiddenError(error.message); + throw new ForbiddenError(error); default: { const _exhaustiveCheck: never = error.code; diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/field-metadata-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/field-metadata-graphql-api-exception-handler.util.ts index 32e3c58ad..ef79c078a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/field-metadata-graphql-api-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/field-metadata-graphql-api-exception-handler.util.ts @@ -18,21 +18,13 @@ export const fieldMetadataGraphqlApiExceptionHandler = (error: Error) => { if (error instanceof FieldMetadataException) { switch (error.code) { case FieldMetadataExceptionCode.FIELD_METADATA_NOT_FOUND: - throw new NotFoundError(error.message, { - userFriendlyMessage: error.userFriendlyMessage, - }); + throw new NotFoundError(error); case FieldMetadataExceptionCode.INVALID_FIELD_INPUT: - throw new UserInputError(error.message, { - userFriendlyMessage: error.userFriendlyMessage, - }); + throw new UserInputError(error); case FieldMetadataExceptionCode.FIELD_MUTATION_NOT_ALLOWED: - throw new ForbiddenError(error.message, { - userFriendlyMessage: error.userFriendlyMessage, - }); + throw new ForbiddenError(error); case FieldMetadataExceptionCode.FIELD_ALREADY_EXISTS: - throw new ConflictError(error.message, { - userFriendlyMessage: error.userFriendlyMessage, - }); + throw new ConflictError(error); case FieldMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND: case FieldMetadataExceptionCode.INTERNAL_SERVER_ERROR: case FieldMetadataExceptionCode.FIELD_METADATA_RELATION_NOT_ENABLED: diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/object-metadata-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/object-metadata-graphql-api-exception-handler.util.ts index 9d8094e4a..077e05923 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/object-metadata-graphql-api-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/object-metadata-graphql-api-exception-handler.util.ts @@ -12,23 +12,19 @@ import { InvalidMetadataException } from 'src/engine/metadata-modules/utils/exce export const objectMetadataGraphqlApiExceptionHandler = (error: Error) => { if (error instanceof InvalidMetadataException) { - throw new UserInputError(error.message); + throw new UserInputError(error); } if (error instanceof ObjectMetadataException) { switch (error.code) { case ObjectMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND: - throw new NotFoundError(error.message); + throw new NotFoundError(error); case ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT: - throw new UserInputError(error.message, { - userFriendlyMessage: error.userFriendlyMessage, - }); + throw new UserInputError(error); case ObjectMetadataExceptionCode.OBJECT_MUTATION_NOT_ALLOWED: - throw new ForbiddenError(error.message); + throw new ForbiddenError(error); case ObjectMetadataExceptionCode.OBJECT_ALREADY_EXISTS: - throw new ConflictError(error.message, { - userFriendlyMessage: error.userFriendlyMessage, - }); + throw new ConflictError(error); case ObjectMetadataExceptionCode.MISSING_CUSTOM_OBJECT_DEFAULT_LABEL_IDENTIFIER_FIELD: throw error; default: { diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.exception.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.exception.ts index 318c0efb4..dd73c08ae 100644 --- a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.exception.ts +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.exception.ts @@ -2,8 +2,12 @@ import { CustomException } from 'src/utils/custom-exception'; export class PermissionsException extends CustomException { declare code: PermissionsExceptionCode; - constructor(message: string, code: PermissionsExceptionCode) { - super(message, code); + constructor( + message: string, + code: PermissionsExceptionCode, + userFriendlyMessage?: string, + ) { + super(message, code, userFriendlyMessage); } } diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/utils/permission-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/utils/permission-graphql-api-exception-handler.util.ts index ea5afd68f..07d16550c 100644 --- a/packages/twenty-server/src/engine/metadata-modules/permissions/utils/permission-graphql-api-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/utils/permission-graphql-api-exception-handler.util.ts @@ -1,5 +1,3 @@ -import { t } from '@lingui/core/macro'; - import { ForbiddenError, NotFoundError, @@ -17,18 +15,17 @@ export const permissionGraphqlApiExceptionHandler = ( case PermissionsExceptionCode.PERMISSION_DENIED: throw new ForbiddenError(error.message, { userFriendlyMessage: 'User does not have permission.', + subCode: error.code, }); case PermissionsExceptionCode.ROLE_LABEL_ALREADY_EXISTS: - throw new ForbiddenError(error.message, { - userFriendlyMessage: t`A role with this label already exists.`, - }); + throw new ForbiddenError(error); case PermissionsExceptionCode.CANNOT_UNASSIGN_LAST_ADMIN: case PermissionsExceptionCode.CANNOT_UPDATE_SELF_ROLE: case PermissionsExceptionCode.CANNOT_DELETE_LAST_ADMIN_USER: case PermissionsExceptionCode.ROLE_NOT_EDITABLE: case PermissionsExceptionCode.CANNOT_ADD_OBJECT_PERMISSION_ON_SYSTEM_OBJECT: case PermissionsExceptionCode.CANNOT_ADD_FIELD_PERMISSION_ON_SYSTEM_OBJECT: - throw new ForbiddenError(error.message); + throw new ForbiddenError(error); case PermissionsExceptionCode.INVALID_ARG: case PermissionsExceptionCode.INVALID_SETTING: case PermissionsExceptionCode.CANNOT_GIVE_WRITING_PERMISSION_ON_NON_READABLE_OBJECT: @@ -37,13 +34,13 @@ export const permissionGraphqlApiExceptionHandler = ( case PermissionsExceptionCode.FIELD_RESTRICTION_ONLY_ALLOWED_ON_READABLE_OBJECT: case PermissionsExceptionCode.FIELD_RESTRICTION_ON_UPDATE_ONLY_ALLOWED_ON_UPDATABLE_OBJECT: case PermissionsExceptionCode.EMPTY_FIELD_PERMISSION_NOT_ALLOWED: - throw new UserInputError(error.message); + throw new UserInputError(error); case PermissionsExceptionCode.ROLE_NOT_FOUND: case PermissionsExceptionCode.USER_WORKSPACE_NOT_FOUND: case PermissionsExceptionCode.OBJECT_METADATA_NOT_FOUND: case PermissionsExceptionCode.FIELD_METADATA_NOT_FOUND: case PermissionsExceptionCode.PERMISSION_NOT_FOUND: - throw new NotFoundError(error.message); + throw new NotFoundError(error); case PermissionsExceptionCode.UPSERT_FIELD_PERMISSION_FAILED: case PermissionsExceptionCode.DEFAULT_ROLE_NOT_FOUND: case PermissionsExceptionCode.WORKSPACE_ID_ROLE_USER_WORKSPACE_MISMATCH: 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 a6885e7b6..47e609e80 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 @@ -1,5 +1,6 @@ import { InjectRepository } from '@nestjs/typeorm'; +import { t } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; import { Repository } from 'typeorm'; @@ -286,6 +287,7 @@ export class RoleService { throw new PermissionsException( PermissionsExceptionMessage.ROLE_LABEL_ALREADY_EXISTS, PermissionsExceptionCode.ROLE_LABEL_ALREADY_EXISTS, + t`A role with this label already exists.`, ); } } diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/utils/serverless-function-graphql-api-exception-handler.utils.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/utils/serverless-function-graphql-api-exception-handler.utils.ts index a2b90a5b5..cdcc86aeb 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/utils/serverless-function-graphql-api-exception-handler.utils.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/utils/serverless-function-graphql-api-exception-handler.utils.ts @@ -14,13 +14,13 @@ export const serverlessFunctionGraphQLApiExceptionHandler = (error: any) => { switch (error.code) { case ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_NOT_FOUND: case ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_VERSION_NOT_FOUND: - throw new NotFoundError(error.message); + throw new NotFoundError(error); case ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_ALREADY_EXIST: - throw new ConflictError(error.message); + throw new ConflictError(error); case ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_NOT_READY: case ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_BUILDING: case ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_EXECUTION_LIMIT_REACHED: - throw new ForbiddenError(error.message); + throw new ForbiddenError(error); case ServerlessFunctionExceptionCode.SERVERLESS_FUNCTION_CODE_UNCHANGED: throw error; default: { diff --git a/packages/twenty-server/test/integration/metadata/suites/field-metadata/__snapshots__/failing-field-metadata-relation-update.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/field-metadata/__snapshots__/failing-field-metadata-relation-update.integration-spec.ts.snap index 762d785e7..5251cb575 100644 --- a/packages/twenty-server/test/integration/metadata/suites/field-metadata/__snapshots__/failing-field-metadata-relation-update.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/field-metadata/__snapshots__/failing-field-metadata-relation-update.integration-spec.ts.snap @@ -5,6 +5,7 @@ exports[`Field metadata relation update should fail relation when name is change { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Name cannot be changed for relation fields", @@ -18,6 +19,7 @@ exports[`Field metadata relation update should fail relation when name is not in { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "New Name should be in camelCase", diff --git a/packages/twenty-server/test/integration/metadata/suites/field-metadata/__snapshots__/update-one-field-metadata-related-record.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/field-metadata/__snapshots__/update-one-field-metadata-related-record.integration-spec.ts.snap index c7e7f1722..9cd5891d5 100644 --- a/packages/twenty-server/test/integration/metadata/suites/field-metadata/__snapshots__/update-one-field-metadata-related-record.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/field-metadata/__snapshots__/update-one-field-metadata-related-record.integration-spec.ts.snap @@ -5,6 +5,7 @@ exports[`update-one-field-metadata-related-record MULTI_SELECT should delete rel { "extensions": { "code": "NOT_FOUND", + "subCode": "RECORD_NOT_FOUND", "userFriendlyMessage": "An error occurred.", }, "message": "Record not found", @@ -95,6 +96,7 @@ exports[`update-one-field-metadata-related-record SELECT should delete related v { "extensions": { "code": "NOT_FOUND", + "subCode": "RECORD_NOT_FOUND", "userFriendlyMessage": "An error occurred.", }, "message": "Record not found", diff --git a/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/create-one-field-metadata-enum.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/create-one-field-metadata-enum.integration-spec.ts.snap index e10d26743..39b6c56f8 100644 --- a/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/create-one-field-metadata-enum.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/create-one-field-metadata-enum.integration-spec.ts.snap @@ -5,6 +5,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -18,6 +19,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -31,6 +33,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Label must not contain a comma", }, "message": "Label must not contain a comma", @@ -44,6 +47,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option id", }, "message": "Duplicated option id", @@ -57,6 +61,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option position", }, "message": "Duplicated option position", @@ -70,6 +75,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option value", }, "message": "Duplicated option value", @@ -83,6 +89,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option value", }, "message": "Duplicated option value", @@ -96,6 +103,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "If defined default value must contain at least one value", }, "message": "If defined default value must contain at least one value", @@ -109,6 +117,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Options are required for enum fields", @@ -122,6 +131,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -135,6 +145,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -148,6 +159,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label "" is beneath 1 character", }, "message": "Option label "" is beneath 1 character", @@ -161,6 +173,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value "" is beneath 1 character", }, "message": "Option value "" is beneath 1 character", @@ -174,6 +187,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value should be as quoted string", }, "message": "Default value should be as quoted string", @@ -187,6 +201,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -200,6 +215,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", }, "message": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", @@ -213,6 +229,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -226,6 +243,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -239,6 +257,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -265,6 +284,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "22222"", }, "message": "Value must be in UPPER_CASE and follow snake_case "22222"", @@ -278,6 +298,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is required", }, "message": "Option id is required", @@ -291,6 +312,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label is required", }, "message": "Option label is required", @@ -304,6 +326,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Options are required for enum fields", @@ -317,6 +340,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value is required", }, "message": "Option value is required", @@ -330,6 +354,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -343,6 +368,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -356,6 +382,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label "" is beneath 1 character", }, "message": "Option label "" is beneath 1 character", @@ -369,6 +396,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value "" is beneath 1 character", }, "message": "Option value "" is beneath 1 character", @@ -382,6 +410,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -395,6 +424,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -408,6 +438,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label exceeds 63 characters", }, "message": "Option label exceeds 63 characters", @@ -421,6 +452,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value exceeds 63 characters", }, "message": "Option value exceeds 63 characters", @@ -434,6 +466,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label is required", }, "message": "Option label is required", @@ -447,6 +480,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value is required", }, "message": "Option value is required", @@ -460,6 +494,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Options are required for enum fields", @@ -473,6 +508,7 @@ exports[`Create field metadata MULTI_SELECT tests suite Create should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value "'UNKNOWN_OPTION'" must be one of the option values", }, "message": "Default value "'UNKNOWN_OPTION'" must be one of the option values", @@ -486,6 +522,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with an inv { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value should be as quoted string", }, "message": "Default value should be as quoted string", @@ -499,6 +536,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with an unk { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value "'OPTION_424242'" must be one of the option values", }, "message": "Default value "'OPTION_424242'" must be one of the option values", @@ -512,6 +550,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with comma { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Label must not contain a comma", }, "message": "Label must not contain a comma", @@ -525,6 +564,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with duplic { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option id", }, "message": "Duplicated option id", @@ -538,6 +578,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with duplic { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option position", }, "message": "Duplicated option position", @@ -551,6 +592,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with duplic { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option value", }, "message": "Duplicated option value", @@ -564,6 +606,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with duplic { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option value", }, "message": "Duplicated option value", @@ -577,6 +620,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with empty { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Options are required for enum fields", @@ -590,6 +634,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with empty { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value should be as quoted string", }, "message": "Default value should be as quoted string", @@ -603,6 +648,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with empty { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -616,6 +662,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with empty { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label "" is beneath 1 character", }, "message": "Option label "" is beneath 1 character", @@ -629,6 +676,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with empty { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value "" is beneath 1 character", }, "message": "Option value "" is beneath 1 character", @@ -642,6 +690,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with invali { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -655,6 +704,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with invali { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", }, "message": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", @@ -668,6 +718,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with not a { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be a stringified array", @@ -681,6 +732,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with not a { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -707,6 +759,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with not a { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "22222"", }, "message": "Value must be in UPPER_CASE and follow snake_case "22222"", @@ -720,6 +773,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with null i { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is required", }, "message": "Option id is required", @@ -733,6 +787,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with null l { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label is required", }, "message": "Option label is required", @@ -746,6 +801,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with null o { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Options are required for enum fields", @@ -759,6 +815,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with null v { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value is required", }, "message": "Option value is required", @@ -772,6 +829,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with only w { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value should be as quoted string", }, "message": "Default value should be as quoted string", @@ -785,6 +843,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with only w { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -798,6 +857,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with only w { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label "" is beneath 1 character", }, "message": "Option label "" is beneath 1 character", @@ -811,6 +871,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with only w { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value "" is beneath 1 character", }, "message": "Option value "" is beneath 1 character", @@ -824,6 +885,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with too lo { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value should be as quoted string", }, "message": "Default value should be as quoted string", @@ -837,6 +899,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with too lo { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -850,6 +913,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with too lo { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label exceeds 63 characters", }, "message": "Option label exceeds 63 characters", @@ -863,6 +927,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with too lo { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value exceeds 63 characters", }, "message": "Option value exceeds 63 characters", @@ -876,6 +941,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with undefi { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label is required", }, "message": "Option label is required", @@ -889,6 +955,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with undefi { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value is required", }, "message": "Option value is required", @@ -902,6 +969,7 @@ exports[`Create field metadata SELECT tests suite Create should fail with undefi { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Options are required for enum fields", diff --git a/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/update-one-enum-field-metadata.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/update-one-enum-field-metadata.integration-spec.ts.snap index 8fc21ee98..2aab0279c 100644 --- a/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/update-one-enum-field-metadata.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/update-one-enum-field-metadata.integration-spec.ts.snap @@ -5,6 +5,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -18,6 +19,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -31,6 +33,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Label must not contain a comma", }, "message": "Label must not contain a comma", @@ -44,6 +47,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option id", }, "message": "Duplicated option id", @@ -57,6 +61,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option position", }, "message": "Duplicated option position", @@ -70,6 +75,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option value", }, "message": "Duplicated option value", @@ -83,6 +89,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option value", }, "message": "Duplicated option value", @@ -96,6 +103,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "If defined default value must contain at least one value", }, "message": "If defined default value must contain at least one value", @@ -109,6 +117,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Options are required for enum fields", @@ -122,6 +131,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -135,6 +145,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -148,6 +159,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label "" is beneath 1 character", }, "message": "Option label "" is beneath 1 character", @@ -161,6 +173,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value "" is beneath 1 character", }, "message": "Option value "" is beneath 1 character", @@ -174,6 +187,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value should be as quoted string", }, "message": "Default value should be as quoted string", @@ -187,6 +201,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -200,6 +215,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", }, "message": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", @@ -213,6 +229,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -226,6 +243,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -239,6 +257,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -265,6 +284,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "22222"", }, "message": "Value must be in UPPER_CASE and follow snake_case "22222"", @@ -278,6 +298,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is required", }, "message": "Option id is required", @@ -291,6 +312,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label is required", }, "message": "Option label is required", @@ -304,6 +326,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value is required", }, "message": "Option value is required", @@ -317,6 +340,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -330,6 +354,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -343,6 +368,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label "" is beneath 1 character", }, "message": "Option label "" is beneath 1 character", @@ -356,6 +382,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value "" is beneath 1 character", }, "message": "Option value "" is beneath 1 character", @@ -369,6 +396,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be an array", @@ -382,6 +410,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -395,6 +424,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label exceeds 63 characters", }, "message": "Option label exceeds 63 characters", @@ -408,6 +438,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value exceeds 63 characters", }, "message": "Option value exceeds 63 characters", @@ -421,6 +452,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label is required", }, "message": "Option label is required", @@ -434,6 +466,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value is required", }, "message": "Option value is required", @@ -447,6 +480,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value "'OPTION_42'" must be one of the option values", }, "message": "Default value "'OPTION_42'" must be one of the option values", @@ -460,6 +494,7 @@ exports[`Update field metadata MULTI_SELECT tests suite Update should fail with { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value "'UNKNOWN_OPTION'" must be one of the option values", }, "message": "Default value "'UNKNOWN_OPTION'" must be one of the option values", @@ -473,6 +508,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with an inv { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value should be as quoted string", }, "message": "Default value should be as quoted string", @@ -486,6 +522,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with an unk { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value "'OPTION_424242'" must be one of the option values", }, "message": "Default value "'OPTION_424242'" must be one of the option values", @@ -499,6 +536,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with comma { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Label must not contain a comma", }, "message": "Label must not contain a comma", @@ -512,6 +550,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with duplic { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option id", }, "message": "Duplicated option id", @@ -525,6 +564,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with duplic { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option position", }, "message": "Duplicated option position", @@ -538,6 +578,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with duplic { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option value", }, "message": "Duplicated option value", @@ -551,6 +592,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with duplic { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Duplicated option value", }, "message": "Duplicated option value", @@ -564,6 +606,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with empty { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Options are required for enum fields", @@ -577,6 +620,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with empty { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value should be as quoted string", }, "message": "Default value should be as quoted string", @@ -590,6 +634,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with empty { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -603,6 +648,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with empty { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label "" is beneath 1 character", }, "message": "Option label "" is beneath 1 character", @@ -616,6 +662,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with empty { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value "" is beneath 1 character", }, "message": "Option value "" is beneath 1 character", @@ -629,6 +676,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with invali { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -642,6 +690,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with invali { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", }, "message": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", @@ -655,6 +704,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with not a { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "An error occurred.", }, "message": "Default value for multi-select must be a stringified array", @@ -668,6 +718,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with not a { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -694,6 +745,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with not a { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "22222"", }, "message": "Value must be in UPPER_CASE and follow snake_case "22222"", @@ -707,6 +759,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with null i { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is required", }, "message": "Option id is required", @@ -720,6 +773,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with null l { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label is required", }, "message": "Option label is required", @@ -733,6 +787,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with null v { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value is required", }, "message": "Option value is required", @@ -746,6 +801,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with only w { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value should be as quoted string", }, "message": "Default value should be as quoted string", @@ -759,6 +815,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with only w { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -772,6 +829,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with only w { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label "" is beneath 1 character", }, "message": "Option label "" is beneath 1 character", @@ -785,6 +843,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with only w { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value "" is beneath 1 character", }, "message": "Option value "" is beneath 1 character", @@ -798,6 +857,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with too lo { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value should be as quoted string", }, "message": "Default value should be as quoted string", @@ -811,6 +871,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with too lo { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option id is invalid", }, "message": "Option id is invalid", @@ -824,6 +885,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with too lo { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label exceeds 63 characters", }, "message": "Option label exceeds 63 characters", @@ -837,6 +899,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with too lo { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value exceeds 63 characters", }, "message": "Option value exceeds 63 characters", @@ -850,6 +913,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with undefi { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option label is required", }, "message": "Option label is required", @@ -863,6 +927,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with undefi { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Option value is required", }, "message": "Option value is required", @@ -876,6 +941,7 @@ exports[`Update field metadata SELECT tests suite Update should fail with unknow { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_FIELD_INPUT", "userFriendlyMessage": "Default value "'OPTION_42'" must be one of the option values", }, "message": "Default value "'OPTION_42'" must be one of the option values", diff --git a/packages/twenty-server/test/integration/metadata/suites/field-metadata/phone/__snapshots__/create-one-field-metadata-phone.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/field-metadata/phone/__snapshots__/create-one-field-metadata-phone.integration-spec.ts.snap index f3236fd1d..e507f7d68 100644 --- a/packages/twenty-server/test/integration/metadata/suites/field-metadata/phone/__snapshots__/create-one-field-metadata-phone.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/field-metadata/phone/__snapshots__/create-one-field-metadata-phone.integration-spec.ts.snap @@ -5,6 +5,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "CONFLICTING_PHONE_CALLING_CODE_AND_COUNTRY_CODE", "userFriendlyMessage": "Provided country code and calling code are conflicting", }, "message": "Provided country code and calling code are conflicting", @@ -18,6 +19,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "CONFLICTING_PHONE_CALLING_CODE_AND_COUNTRY_CODE", "userFriendlyMessage": "Provided country code and calling code are conflicting", }, "message": "Provided country code and calling code are conflicting", @@ -31,6 +33,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "CONFLICTING_PHONE_CALLING_CODE", "userFriendlyMessage": "Provided and inferred calling code are conflicting", }, "message": "Provided and inferred calling code are conflicting", @@ -44,6 +47,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "CONFLICTING_PHONE_CALLING_CODE", "userFriendlyMessage": "Provided and inferred calling code are conflicting", }, "message": "Provided and inferred calling code are conflicting", @@ -57,6 +61,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "CONFLICTING_PHONE_COUNTRY_CODE", "userFriendlyMessage": "Provided and inferred country code are conflicting", }, "message": "Provided and inferred country code are conflicting", @@ -70,6 +75,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "CONFLICTING_PHONE_COUNTRY_CODE", "userFriendlyMessage": "Provided and inferred country code are conflicting", }, "message": "Provided and inferred country code are conflicting", @@ -83,6 +89,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_PHONE_CALLING_CODE", "userFriendlyMessage": "Invalid calling code +999", }, "message": "Invalid calling code +999", @@ -96,6 +103,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_PHONE_CALLING_CODE", "userFriendlyMessage": "Invalid calling code +999", }, "message": "Invalid calling code +999", @@ -109,6 +117,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_PHONE_COUNTRY_CODE", "userFriendlyMessage": "Invalid country code XX", }, "message": "Invalid country code XX", @@ -122,6 +131,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_PHONE_COUNTRY_CODE", "userFriendlyMessage": "Invalid country code XX", }, "message": "Invalid country code XX", @@ -135,6 +145,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_PHONE_NUMBER", "userFriendlyMessage": "Provided phone number is invalid not-a-number", }, "message": "Provided phone number is invalid not-a-number", @@ -148,6 +159,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_PHONE_NUMBER", "userFriendlyMessage": "Provided phone number is invalid not-a-number", }, "message": "Provided phone number is invalid not-a-number", @@ -161,6 +173,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_PHONE_NUMBER", "userFriendlyMessage": "Provided phone number is invalid 123456789", }, "message": "Provided phone number is invalid 123456789", @@ -174,6 +187,7 @@ exports[`Phone field metadata tests suite It should fail to create primary phone { "extensions": { "code": "BAD_USER_INPUT", + "subCode": "INVALID_PHONE_NUMBER", "userFriendlyMessage": "Provided phone number is invalid 123456789", }, "message": "Provided phone number is invalid 123456789",