Capture FE GraphQL exceptions in sentry (#12286)

We should capture graphQL exceptions thrown in the FE in Sentry.

All the more so as we have just cleaned back-end errors in sentry,
preventing 4xx errors from being wrongfully sent to sentry.
Those 4xx errors should, except for `Unauthenticated` and `Forbidden`
errors (for now - this list can evolve), trigger a sentry FE error, as
we are not suppose to let users of the product interface trigger queries
that will fail with 4xx errors (for instance a malformed input).

We still miss an efficient way to group those errors together in sentry.
It could be the message but the message may be different for each user
if it contains user-specific data, and we don't always have control on
the message.
This can be done later as we iterate on improving sentry
This commit is contained in:
Marie
2025-05-26 19:23:19 +02:00
committed by GitHub
parent a15451dab2
commit 69badf2a66
2 changed files with 8 additions and 3 deletions

View File

@ -17,13 +17,14 @@ import { AuthTokenPair } from '~/generated/graphql';
import { logDebug } from '~/utils/logDebug'; import { logDebug } from '~/utils/logDebug';
import { i18n } from '@lingui/core'; import { i18n } from '@lingui/core';
import { captureException } from '@sentry/react';
import { GraphQLFormattedError } from 'graphql'; import { GraphQLFormattedError } from 'graphql';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { cookieStorage } from '~/utils/cookie-storage'; import { cookieStorage } from '~/utils/cookie-storage';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
import { ApolloManager } from '../types/apolloManager.interface'; import { ApolloManager } from '../types/apolloManager.interface';
import { loggerLink } from '../utils/loggerLink';
import { getTokenPair } from '../utils/getTokenPair'; import { getTokenPair } from '../utils/getTokenPair';
import { loggerLink } from '../utils/loggerLink';
const logger = loggerLink(() => 'Twenty'); const logger = loggerLink(() => 'Twenty');
@ -133,6 +134,9 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
}), }),
).flatMap(() => forward(operation)); ).flatMap(() => forward(operation));
} }
case 'FORBIDDEN': {
return;
}
default: default:
if (isDebugMode === true) { if (isDebugMode === true) {
logDebug( logDebug(
@ -145,6 +149,7 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
}, Path: ${graphQLError.path}`, }, Path: ${graphQLError.path}`,
); );
} }
captureException(graphQLError);
} }
} }
} }

View File

@ -88,9 +88,9 @@ export class FieldMetadataRelationService {
const sourceObjectMetadata = objectMetadataMaps.byId[objectMetadataId]; const sourceObjectMetadata = objectMetadataMaps.byId[objectMetadataId];
const targetObjectMetadata = const targetObjectMetadata =
objectMetadataMaps.byId[relationTargetObjectMetadataId]; objectMetadataMaps.byId[relationTargetObjectMetadataId];
const sourceFieldMetadata = sourceObjectMetadata.fieldsById[id]; const sourceFieldMetadata = sourceObjectMetadata?.fieldsById[id];
const targetFieldMetadata = const targetFieldMetadata =
targetObjectMetadata.fieldsById[relationTargetFieldMetadataId]; targetObjectMetadata?.fieldsById[relationTargetFieldMetadataId];
if ( if (
!sourceObjectMetadata || !sourceObjectMetadata ||