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 5c28d63f3..3d2e2b7e1 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 332fc08c7..1ab7764f5 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 11a72c026..2cc0b571b 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 000000000..ae592e22c --- /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 000000000..0f98cdcfd --- /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 000000000..35201e31b --- /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 000000000..f801e9be7 --- /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 6bdc67d43..790c36ab2 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 cdfae3bf7..bb4522796 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 eeef6e280..5ff6bf161 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 6961b65bf..ef00ed60f 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 89a66cfb8..4367e4035 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 b7d65a9c1..13e2c976a 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 394eb7330..e289d02af 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 80cc0149c..7bb281278 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); };