From 1dff5bf95794c26a1241ecdb87cb86b407502f87 Mon Sep 17 00:00:00 2001 From: Weiko Date: Fri, 12 Jul 2024 17:56:21 +0200 Subject: [PATCH] Fix custom errors thrown as 500 (#6238) We call convertExceptionToGraphQLError in the exception handler for http exceptions but we don't take into account those that already are graphqlErrors and because of that the logic of convertExceptionToGraphql is to fallback to a 500. Now if the exception is a BaseGraphqlError (custom graphql error we throw in the code), we throw them directly. BEFORE Screenshot 2024-07-12 at 15 33 03 AFTER Screenshot 2024-07-12 at 15 32 01 --------- Co-authored-by: Charles Bochet --- .../api/graphql/metadata.module-factory.ts | 12 +- .../workspace-query-runner.service.ts | 38 ++--- .../api/rest/errors/RestApiException.ts | 2 +- .../graphql/engine-graphql.module.ts | 11 ++ .../hooks/use-graphql-error-handler.hook.ts | 133 ++++++++++++++++++ .../generate-graphql-error-from-error.util.ts | 18 +++ .../graphql}/utils/graphql-errors.util.ts | 0 .../utils/should-capture-exception.util.ts | 26 ++++ .../postgres-credentials.service.ts | 8 +- .../hooks/use-exception-handler.hook.ts | 9 +- ...data-graphql-api-exception-handler.util.ts | 14 +- ...data-graphql-api-exception-handler.util.ts | 14 +- ...data-graphql-api-exception-handler.util.ts | 12 +- ...able-graphql-api-exception-handler.util.ts | 12 +- ...rver-graphql-api-exception-handler.util.ts | 14 +- .../utils/global-exception-handler.util.ts | 15 +- 16 files changed, 266 insertions(+), 72 deletions(-) create mode 100644 packages/twenty-server/src/engine/core-modules/graphql/engine-graphql.module.ts create mode 100644 packages/twenty-server/src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook.ts create mode 100644 packages/twenty-server/src/engine/core-modules/graphql/utils/generate-graphql-error-from-error.util.ts rename packages/twenty-server/src/engine/{ => core-modules/graphql}/utils/graphql-errors.util.ts (100%) create mode 100644 packages/twenty-server/src/engine/core-modules/graphql/utils/should-capture-exception.util.ts diff --git a/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts b/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts index 5c28d63f394..3d2e2b7e158 100644 --- a/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts +++ b/packages/twenty-server/src/engine/api/graphql/metadata.module-factory.ts @@ -1,15 +1,15 @@ import { YogaDriverConfig } from '@graphql-yoga/nestjs'; import GraphQLJSON from 'graphql-type-json'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; -import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; -import { useExceptionHandler } from 'src/engine/integrations/exception-handler/hooks/use-exception-handler.hook'; +import { useCachedMetadata } from 'src/engine/api/graphql/graphql-config/hooks/use-cached-metadata'; import { useThrottler } from 'src/engine/api/graphql/graphql-config/hooks/use-throttler'; import { MetadataGraphQLApiModule } from 'src/engine/api/graphql/metadata-graphql-api.module'; -import { renderApolloPlayground } from 'src/engine/utils/render-apollo-playground.util'; +import { useGraphQLErrorHandlerHook } from 'src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook'; import { DataloaderService } from 'src/engine/dataloaders/dataloader.service'; -import { useCachedMetadata } from 'src/engine/api/graphql/graphql-config/hooks/use-cached-metadata'; import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service'; +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; +import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; +import { renderApolloPlayground } from 'src/engine/utils/render-apollo-playground.util'; export const metadataModuleFactory = async ( environmentService: EnvironmentService, @@ -32,7 +32,7 @@ export const metadataModuleFactory = async ( return context.req.user?.id ?? context.req.ip ?? 'anonymous'; }, }), - useExceptionHandler({ + useGraphQLErrorHandlerHook({ exceptionHandlerService, }), useCachedMetadata({ diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts index 332fc08c7b1..1ab7764f554 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-query-runner/workspace-query-runner.service.ts @@ -9,12 +9,12 @@ import { EventEmitter2 } from '@nestjs/event-emitter'; import isEmpty from 'lodash.isempty'; import { DataSource } from 'typeorm'; -import { IConnection } from 'src/engine/api/graphql/workspace-query-runner/interfaces/connection.interface'; import { Record as IRecord, RecordFilter, RecordOrderBy, } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; +import { IConnection } from 'src/engine/api/graphql/workspace-query-runner/interfaces/connection.interface'; import { CreateManyResolverArgs, CreateOneResolverArgs, @@ -30,36 +30,36 @@ import { import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface'; import { WorkspaceQueryBuilderFactory } from 'src/engine/api/graphql/workspace-query-builder/workspace-query-builder.factory'; -import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; -import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; -import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { QueryResultGettersFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters.factory'; +import { QueryRunnerArgsFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory'; import { CallWebhookJobsJob, CallWebhookJobsJobData, CallWebhookJobsJobOperation, } from 'src/engine/api/graphql/workspace-query-runner/jobs/call-webhook-jobs.job'; -import { parseResult } from 'src/engine/api/graphql/workspace-query-runner/utils/parse-result.util'; -import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; -import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event'; -import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event'; -import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; -import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; -import { NotFoundError } from 'src/engine/utils/graphql-errors.util'; -import { QueryRunnerArgsFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory'; -import { QueryResultGettersFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters.factory'; -import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util'; -import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; import { assertIsValidUuid } from 'src/engine/api/graphql/workspace-query-runner/utils/assert-is-valid-uuid.util'; -import { isQueryTimeoutError } from 'src/engine/utils/query-timeout.util'; -import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { parseResult } from 'src/engine/api/graphql/workspace-query-runner/utils/parse-result.util'; +import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service'; import { DuplicateService } from 'src/engine/core-modules/duplicate/duplicate.service'; +import { NotFoundError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; +import { ObjectRecordCreateEvent } from 'src/engine/integrations/event-emitter/types/object-record-create.event'; +import { ObjectRecordDeleteEvent } from 'src/engine/integrations/event-emitter/types/object-record-delete.event'; +import { ObjectRecordUpdateEvent } from 'src/engine/integrations/event-emitter/types/object-record-update.event'; +import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator'; +import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants'; +import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service'; +import { assertMutationNotOnRemoteObject } from 'src/engine/metadata-modules/object-metadata/utils/assert-mutation-not-on-remote-object.util'; +import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; +import { isQueryTimeoutError } from 'src/engine/utils/query-timeout.util'; +import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; +import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; -import { WorkspaceQueryRunnerOptions } from './interfaces/query-runner-option.interface'; import { PGGraphQLMutation, PGGraphQLResult, } from './interfaces/pg-graphql.interface'; +import { WorkspaceQueryRunnerOptions } from './interfaces/query-runner-option.interface'; import { PgGraphQLConfig, computePgGraphQLError, diff --git a/packages/twenty-server/src/engine/api/rest/errors/RestApiException.ts b/packages/twenty-server/src/engine/api/rest/errors/RestApiException.ts index 11a72c02623..2cc0b571b7e 100644 --- a/packages/twenty-server/src/engine/api/rest/errors/RestApiException.ts +++ b/packages/twenty-server/src/engine/api/rest/errors/RestApiException.ts @@ -1,6 +1,6 @@ import { BadRequestException } from '@nestjs/common'; -import { BaseGraphQLError } from 'src/engine/utils/graphql-errors.util'; +import { BaseGraphQLError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; const formatMessage = (message: BaseGraphQLError) => { if (message.extensions) { diff --git a/packages/twenty-server/src/engine/core-modules/graphql/engine-graphql.module.ts b/packages/twenty-server/src/engine/core-modules/graphql/engine-graphql.module.ts new file mode 100644 index 00000000000..ae592e22c80 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/graphql/engine-graphql.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; + +import { useGraphQLErrorHandlerHook } from 'src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook'; +import { ExceptionHandlerModule } from 'src/engine/integrations/exception-handler/exception-handler.module'; + +@Module({ + imports: [ExceptionHandlerModule], + exports: [useGraphQLErrorHandlerHook], + providers: [], +}) +export class EngineGraphQLModule {} diff --git a/packages/twenty-server/src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook.ts b/packages/twenty-server/src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook.ts new file mode 100644 index 00000000000..0f98cdcfdb4 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook.ts @@ -0,0 +1,133 @@ +import { + OnExecuteDoneHookResultOnNextHook, + Plugin, + getDocumentString, + handleStreamOrSingleExecutionResult, +} from '@envelop/core'; +import { GraphQLError, Kind, OperationDefinitionNode, print } from 'graphql'; + +import { GraphQLContext } from 'src/engine/api/graphql/graphql-config/interfaces/graphql-context.interface'; + +import { generateGraphQLErrorFromError } from 'src/engine/core-modules/graphql/utils/generate-graphql-error-from-error.util'; +import { BaseGraphQLError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; +import { shouldCaptureException } from 'src/engine/core-modules/graphql/utils/should-capture-exception.util'; +import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; + +type GraphQLErrorHandlerHookOptions = { + /** + * The exception handler service to use. + */ + exceptionHandlerService: ExceptionHandlerService; + /** + * The key of the event id in the error's extension. `null` to disable. + * @default exceptionEventId + */ + eventIdKey?: string | null; +}; + +export const useGraphQLErrorHandlerHook = < + PluginContext extends GraphQLContext, +>( + options: GraphQLErrorHandlerHookOptions, +): Plugin => { + const eventIdKey = options.eventIdKey === null ? null : 'exceptionEventId'; + + function addEventId( + err: GraphQLError, + eventId: string | undefined | null, + ): GraphQLError { + if (eventIdKey !== null && eventId) { + err.extensions[eventIdKey] = eventId; + } + + return err; + } + + return { + async onExecute({ args }) { + const exceptionHandlerService = options.exceptionHandlerService; + const rootOperation = args.document.definitions.find( + (o) => o.kind === Kind.OPERATION_DEFINITION, + ) as OperationDefinitionNode; + const operationType = rootOperation.operation; + const user = args.contextValue.req.user; + const document = getDocumentString(args.document, print); + const opName = + args.operationName || + rootOperation.name?.value || + 'Anonymous Operation'; + + return { + onExecuteDone(payload) { + const handleResult: OnExecuteDoneHookResultOnNextHook = ({ + result, + setResult, + }) => { + if (result.errors && result.errors.length > 0) { + const errorsToCapture = result.errors.reduce( + (acc, error) => { + if (!(error instanceof BaseGraphQLError)) { + error = generateGraphQLErrorFromError(error); + } + + if (shouldCaptureException(error)) { + acc.push(error); + } + + return acc; + }, + [], + ); + + if (errorsToCapture.length > 0) { + const eventIds = exceptionHandlerService.captureExceptions( + errorsToCapture, + { + operation: { + name: opName, + type: operationType, + }, + document, + user, + }, + ); + + errorsToCapture.map((err, i) => addEventId(err, eventIds?.[i])); + } + + const nonCapturedErrors = result.errors.filter( + (error) => !errorsToCapture.includes(error), + ); + + setResult({ + ...result, + errors: [...nonCapturedErrors, ...errorsToCapture], + }); + } + }; + + return handleStreamOrSingleExecutionResult(payload, handleResult); + }, + }; + }, + onValidate: ({ context, validateFn, params: { documentAST, schema } }) => { + const errors = validateFn(schema, documentAST); + + if (Array.isArray(errors) && errors.length > 0) { + const headers = context.req.headers; + const currentSchemaVersion = context.req.cacheVersion; + + const requestSchemaVersion = headers['x-schema-version']; + + if ( + requestSchemaVersion && + requestSchemaVersion !== currentSchemaVersion + ) { + throw new GraphQLError( + `Schema version mismatch, please refresh the page.`, + ); + } + } + }, + }; +}; diff --git a/packages/twenty-server/src/engine/core-modules/graphql/utils/generate-graphql-error-from-error.util.ts b/packages/twenty-server/src/engine/core-modules/graphql/utils/generate-graphql-error-from-error.util.ts new file mode 100644 index 00000000000..35201e31bd7 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/graphql/utils/generate-graphql-error-from-error.util.ts @@ -0,0 +1,18 @@ +import { + BaseGraphQLError, + ErrorCode, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; + +export const generateGraphQLErrorFromError = (error: Error) => { + const graphqlError = new BaseGraphQLError( + error.name, + ErrorCode.INTERNAL_SERVER_ERROR, + ); + + if (process.env.NODE_ENV === 'development') { + graphqlError.stack = error.stack; + graphqlError.extensions['response'] = error.message; + } + + return error; +}; diff --git a/packages/twenty-server/src/engine/utils/graphql-errors.util.ts b/packages/twenty-server/src/engine/core-modules/graphql/utils/graphql-errors.util.ts similarity index 100% rename from packages/twenty-server/src/engine/utils/graphql-errors.util.ts rename to packages/twenty-server/src/engine/core-modules/graphql/utils/graphql-errors.util.ts diff --git a/packages/twenty-server/src/engine/core-modules/graphql/utils/should-capture-exception.util.ts b/packages/twenty-server/src/engine/core-modules/graphql/utils/should-capture-exception.util.ts new file mode 100644 index 00000000000..f801e9be71a --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/graphql/utils/should-capture-exception.util.ts @@ -0,0 +1,26 @@ +import { + BaseGraphQLError, + ErrorCode, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; + +export const graphQLErrorCodesToFilter = [ + ErrorCode.GRAPHQL_VALIDATION_FAILED, + ErrorCode.UNAUTHENTICATED, + ErrorCode.FORBIDDEN, + ErrorCode.NOT_FOUND, + ErrorCode.METHOD_NOT_ALLOWED, + ErrorCode.TIMEOUT, + ErrorCode.CONFLICT, + ErrorCode.BAD_USER_INPUT, +]; + +export const shouldCaptureException = (exception: Error): boolean => { + if ( + exception instanceof BaseGraphQLError && + graphQLErrorCodesToFilter.includes(exception?.extensions?.code) + ) { + return true; + } + + return false; +}; diff --git a/packages/twenty-server/src/engine/core-modules/postgres-credentials/postgres-credentials.service.ts b/packages/twenty-server/src/engine/core-modules/postgres-credentials/postgres-credentials.service.ts index 6bdc67d43c9..790c36ab266 100644 --- a/packages/twenty-server/src/engine/core-modules/postgres-credentials/postgres-credentials.service.ts +++ b/packages/twenty-server/src/engine/core-modules/postgres-credentials/postgres-credentials.service.ts @@ -1,5 +1,5 @@ -import { InjectRepository } from '@nestjs/typeorm'; import { BadRequestException } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; import { randomBytes } from 'crypto'; @@ -9,10 +9,10 @@ import { decryptText, encryptText, } from 'src/engine/core-modules/auth/auth.util'; -import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; -import { PostgresCredentials } from 'src/engine/core-modules/postgres-credentials/postgres-credentials.entity'; -import { NotFoundError } from 'src/engine/utils/graphql-errors.util'; +import { NotFoundError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PostgresCredentialsDTO } from 'src/engine/core-modules/postgres-credentials/dtos/postgres-credentials.dto'; +import { PostgresCredentials } from 'src/engine/core-modules/postgres-credentials/postgres-credentials.entity'; +import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; export class PostgresCredentialsService { constructor( diff --git a/packages/twenty-server/src/engine/integrations/exception-handler/hooks/use-exception-handler.hook.ts b/packages/twenty-server/src/engine/integrations/exception-handler/hooks/use-exception-handler.hook.ts index cdfae3bf760..bb4522796c3 100644 --- a/packages/twenty-server/src/engine/integrations/exception-handler/hooks/use-exception-handler.hook.ts +++ b/packages/twenty-server/src/engine/integrations/exception-handler/hooks/use-exception-handler.hook.ts @@ -1,10 +1,10 @@ -import { GraphQLError, Kind, OperationDefinitionNode, print } from 'graphql'; import { - getDocumentString, - handleStreamOrSingleExecutionResult, OnExecuteDoneHookResultOnNextHook, Plugin, + getDocumentString, + handleStreamOrSingleExecutionResult, } from '@envelop/core'; +import { GraphQLError, Kind, OperationDefinitionNode, print } from 'graphql'; import { GraphQLContext } from 'src/engine/api/graphql/graphql-config/interfaces/graphql-context.interface'; @@ -26,6 +26,9 @@ export type ExceptionHandlerPluginOptions = { eventIdKey?: string | null; }; +// This hook is deprecated. +// We should either handle exception in the context of graphql, controller or command +// @deprecated export const useExceptionHandler = ( options: ExceptionHandlerPluginOptions, ): Plugin => { 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 eeef6e28038..5ff6bf16169 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 @@ -1,14 +1,14 @@ +import { + ConflictError, + ForbiddenError, + InternalServerError, + NotFoundError, + UserInputError, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { FieldMetadataException, FieldMetadataExceptionCode, } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; -import { - UserInputError, - ForbiddenError, - ConflictError, - InternalServerError, - NotFoundError, -} from 'src/engine/utils/graphql-errors.util'; export const fieldMetadataGraphqlApiExceptionHandler = (error: Error) => { if (error instanceof FieldMetadataException) { 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 6961b65bf00..ef00ed60f9f 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 @@ -1,14 +1,14 @@ +import { + ConflictError, + ForbiddenError, + InternalServerError, + NotFoundError, + UserInputError, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { ObjectMetadataException, ObjectMetadataExceptionCode, } from 'src/engine/metadata-modules/object-metadata/object-metadata.exception'; -import { - UserInputError, - ForbiddenError, - ConflictError, - InternalServerError, - NotFoundError, -} from 'src/engine/utils/graphql-errors.util'; export const objectMetadataGraphqlApiExceptionHandler = (error: Error) => { if (error instanceof ObjectMetadataException) { diff --git a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/utils/relation-metadata-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/utils/relation-metadata-graphql-api-exception-handler.util.ts index 89a66cfb814..4367e403512 100644 --- a/packages/twenty-server/src/engine/metadata-modules/relation-metadata/utils/relation-metadata-graphql-api-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/relation-metadata/utils/relation-metadata-graphql-api-exception-handler.util.ts @@ -1,13 +1,13 @@ +import { + ConflictError, + InternalServerError, + NotFoundError, + UserInputError, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { RelationMetadataException, RelationMetadataExceptionCode, } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.exception'; -import { - UserInputError, - ConflictError, - InternalServerError, - NotFoundError, -} from 'src/engine/utils/graphql-errors.util'; export const relationMetadataGraphqlApiExceptionHandler = (error: Error) => { if (error instanceof RelationMetadataException) { diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/utils/remote-table-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/utils/remote-table-graphql-api-exception-handler.util.ts index b7d65a9c1b1..13e2c976a62 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/utils/remote-table-graphql-api-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/remote-table/utils/remote-table-graphql-api-exception-handler.util.ts @@ -1,13 +1,13 @@ +import { + ConflictError, + InternalServerError, + NotFoundError, + UserInputError, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { RemoteTableException, RemoteTableExceptionCode, } from 'src/engine/metadata-modules/remote-server/remote-table/remote-table.exception'; -import { - UserInputError, - ConflictError, - InternalServerError, - NotFoundError, -} from 'src/engine/utils/graphql-errors.util'; export const remoteTableGraphqlApiExceptionHandler = (error: Error) => { if (error instanceof RemoteTableException) { diff --git a/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/remote-server-graphql-api-exception-handler.util.ts b/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/remote-server-graphql-api-exception-handler.util.ts index 394eb733029..e289d02af49 100644 --- a/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/remote-server-graphql-api-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/remote-server/utils/remote-server-graphql-api-exception-handler.util.ts @@ -1,14 +1,14 @@ +import { + ConflictError, + ForbiddenError, + InternalServerError, + NotFoundError, + UserInputError, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { RemoteServerException, RemoteServerExceptionCode, } from 'src/engine/metadata-modules/remote-server/remote-server.exception'; -import { - UserInputError, - ForbiddenError, - ConflictError, - InternalServerError, - NotFoundError, -} from 'src/engine/utils/graphql-errors.util'; export const remoteServerGraphqlApiExceptionHandler = (error: any) => { if (error instanceof RemoteServerException) { diff --git a/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts b/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts index 80cc0149c53..7bb281278a9 100644 --- a/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts +++ b/packages/twenty-server/src/engine/utils/global-exception-handler.util.ts @@ -7,14 +7,14 @@ import { ExceptionHandlerUser } from 'src/engine/integrations/exception-handler/ import { AuthenticationError, BaseGraphQLError, - ForbiddenError, - ValidationError, - NotFoundError, ConflictError, - MethodNotAllowedError, - TimeoutError, ErrorCode, -} from 'src/engine/utils/graphql-errors.util'; + ForbiddenError, + MethodNotAllowedError, + NotFoundError, + TimeoutError, + ValidationError, +} from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; const graphQLPredefinedExceptions = { @@ -88,6 +88,9 @@ export const convertExceptionToGraphQLError = ( if (exception instanceof HttpException) { return convertHttpExceptionToGraphql(exception); } + if (exception instanceof BaseGraphQLError) { + return exception; + } return convertExceptionToGraphql(exception); };