Skip to content

Commit 8746502

Browse files
authored
[LOGS-1] PLU-557: Less verbose error logs (#1208)
## TL;DR This PR enhances error handling for GraphQL requests: - Adds special handling for `INTERNAL_SERVER_ERROR` responses to prevent leaking sensitive server details to the frontend ## How to test? - [ ] Force an error, ensure that the generic 'An error has occurred' toast is thrown on the frontend - [ ] Console should not show any additional information about queries - [ ] If the query has a custom message, it should be shown in the toast in the frontend. for example, when attempting to transfer a pipe to a user that does not exist in Plumber ## Screenshots ![Screenshot 2025-09-15 at 2.08.55 PM.png](https://app.graphite.dev/user-attachments/assets/9e6e4ee9-308a-4a82-863e-ac4cbe57f477.png) ![Screenshot 2025-09-15 at 2.09.23 PM.png](https://app.graphite.dev/user-attachments/assets/a5d90fda-9fb6-4502-93ba-97d7a2a01ae0.png)
1 parent 17bbb48 commit 8746502

File tree

2 files changed

+32
-6
lines changed

2 files changed

+32
-6
lines changed

packages/backend/src/helpers/graphql-instance.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { ApolloServer, type ApolloServerPlugin } from '@apollo/server'
2+
import { unwrapResolverError } from '@apollo/server/errors'
23
import { ApolloServerPluginLandingPageDisabled } from '@apollo/server/plugin/disabled'
34
import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default'
45
import { expressMiddleware } from '@as-integrations/express4'
56
import { makeExecutableSchema } from '@graphql-tools/schema'
67
import { RequestHandler } from 'express'
78
import { Kind, OperationDefinitionNode } from 'graphql/language'
89
import { applyMiddleware } from 'graphql-middleware'
10+
import { DBError } from 'objection'
911

1012
import appConfig from '@/config/app'
1113
import { BadUserInputError } from '@/errors/graphql-errors'
@@ -86,20 +88,42 @@ export const server = new ApolloServer<UnauthenticatedContext>({
8688
],
8789
// We don't want to allow batching within a single HTTP request, this defaults to false
8890
allowBatchedHttpRequests: false,
89-
formatError: (error) => {
90-
logger.error(error)
91-
let errorMessage = error.message
92-
if (error.message.includes('Did you mean')) {
91+
formatError: (formattedError, error) => {
92+
logger.error(formattedError)
93+
94+
// NOTE: objection throws all error with DBError class
95+
// so we handle them here
96+
if (unwrapResolverError(error) instanceof DBError) {
97+
return { message: 'Internal server error', code: 'INTERNAL_SERVER_ERROR' }
98+
}
99+
100+
// NOTE: handles INTERNAL_SERVER_ERROR
101+
// logs the error on the server and return a generic message to the frontend
102+
// to prevent leaking internal server error details to the frontend such as the
103+
// exact SQL queries.
104+
if (formattedError.extensions?.code === 'INTERNAL_SERVER_ERROR') {
105+
// Return a generic message to the frontend
106+
let message = 'An error has occurred'
107+
if (formattedError?.message) {
108+
message += ': ' + formattedError?.message
109+
}
110+
return { message, code: 'INTERNAL_SERVER_ERROR' }
111+
}
112+
113+
let errorMessage = formattedError.message
114+
if (formattedError.message.includes('Did you mean')) {
93115
errorMessage = 'Invalid request'
94116
}
95117
if (
96-
error.message.includes("Please either specify a 'content-type' header")
118+
formattedError.message.includes(
119+
"Please either specify a 'content-type' header",
120+
)
97121
) {
98122
errorMessage = 'Blocked request'
99123
}
100124
const newError = {
101125
message: errorMessage,
102-
code: error.extensions?.code,
126+
code: formattedError.extensions?.code,
103127
}
104128
return newError
105129
},

packages/frontend/src/components/ApolloProvider/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const ApolloProvider = (props: ApolloProviderProps): React.ReactElement => {
1515
(message: string) => {
1616
toast({
1717
title: message,
18+
description:
19+
'If this error persists, contact us at [email protected].',
1820
status: 'error',
1921
duration: 3000,
2022
isClosable: true,

0 commit comments

Comments
 (0)