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 5c28d63f39..3d2e2b7e15 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 332fc08c7b..1ab7764f55 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 11a72c0262..2cc0b571b7 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 0000000000..ae592e22c8 --- /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 0000000000..0f98cdcfdb --- /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 0000000000..35201e31bd --- /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 0000000000..f801e9be71 --- /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 6bdc67d43c..790c36ab26 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 cdfae3bf76..bb4522796c 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 eeef6e2803..5ff6bf1616 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 6961b65bf0..ef00ed60f9 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 89a66cfb81..4367e40351 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 b7d65a9c1b..13e2c976a6 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 394eb73302..e289d02af4 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 80cc0149c5..7bb281278a 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); };