Skip to content

Commit 0e93d5f

Browse files
committed
coordinate is never serialized, but should apear in error instance
1 parent 371548a commit 0e93d5f

File tree

4 files changed

+107
-147
lines changed

4 files changed

+107
-147
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@
107107
},
108108
"overrides": {
109109
"axios": "1.13.2",
110-
"@graphql-tools/executor": "1.5.0-alpha-20251113162628-fc5dd9a67f15da93da0f992ac3e357a9431c42bc",
111-
"@graphql-tools/utils": "10.11.0-alpha-20251113162628-fc5dd9a67f15da93da0f992ac3e357a9431c42bc",
110+
"@graphql-tools/executor": "1.5.0-alpha-20251120140925-6fcd4c6ff2d2eb40d5890db29418a15cc4cc3956",
111+
"@graphql-tools/utils": "10.11.0-alpha-20251120140925-6fcd4c6ff2d2eb40d5890db29418a15cc4cc3956",
112112
"estree-util-value-to-estree": "3.5.0",
113113
"eslint-plugin-unicorn": "56.0.1",
114114
"esbuild": "0.25.12",

packages/graphql-yoga/__tests__/error-masking.spec.ts

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ExecutionResult, GraphQLError } from 'graphql';
12
import { inspect } from '@graphql-tools/utils';
23
import { createGraphQLError, createLogger, createSchema, createYoga } from '../src/index.js';
34
import { useErrorCoordinate } from '../src/plugins/use-error-coordinate.js';
@@ -862,12 +863,17 @@ describe('error masking', () => {
862863
});
863864

864865
it('should mask experimental coordinate error attribute on production env', async () => {
866+
let error: GraphQLError | undefined;
865867
const yoga = createYoga({
866868
logging: false,
867-
maskedErrors: {
868-
isDev: true,
869-
},
870-
plugins: [useErrorCoordinate()],
869+
plugins: [
870+
useErrorCoordinate(),
871+
{
872+
onExecutionResult({ result }) {
873+
error = (result as ExecutionResult).errors?.[0];
874+
},
875+
},
876+
],
871877
schema: createSchema({
872878
typeDefs: /* GraphQL */ `
873879
type Query {
@@ -888,46 +894,36 @@ describe('error masking', () => {
888894
}),
889895
});
890896

891-
const response = await yoga.fetch('http://yoga/graphql', {
897+
const r1 = await yoga.fetch('http://yoga/graphql', {
892898
method: 'POST',
893899
headers: {
894900
accept: 'application/graphql-response+json',
895901
'content-type': 'application/json',
896902
},
897903
body: JSON.stringify({ query: '{ a }' }),
898904
});
905+
const b1 = await r1.json();
899906

900-
const body = await response.json();
901-
expect(response.status).toEqual(200);
902-
903-
expect(body).toMatchObject({
904-
errors: [
905-
{
906-
message: 'Test Error',
907-
coordinate: 'Query.a',
908-
},
909-
],
907+
expect(error).toMatchObject({
908+
message: 'Test Error',
909+
coordinate: 'Query.a',
910910
});
911+
expect(b1.errors[0].coordinate).toBeUndefined();
911912

912-
const response2 = await yoga.fetch('http://yoga/graphql', {
913+
const r2 = await yoga.fetch('http://yoga/graphql', {
913914
method: 'POST',
914915
headers: {
915916
accept: 'application/graphql-response+json',
916917
'content-type': 'application/json',
917918
},
918919
body: JSON.stringify({ query: '{ b }' }),
919920
});
921+
const b2 = await r2.json();
920922

921-
const body2 = await response2.json();
922-
expect(response2.status).toEqual(200);
923-
924-
expect(body2).toMatchObject({
925-
errors: [
926-
{
927-
message: 'Unexpected error.',
928-
coordinate: 'Query.b',
929-
},
930-
],
923+
expect(error).toMatchObject({
924+
message: 'Unexpected error.',
925+
coordinate: 'Query.b',
931926
});
927+
expect(b2.errors[0].coordinate).toBeUndefined();
932928
});
933929
});
Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,7 @@
1-
import { GraphQLError, GraphQLFormattedError } from 'graphql';
21
import { createGraphQLError, getSchemaCoordinate } from '@graphql-tools/utils';
32
import { isGraphQLError, isOriginalGraphQLError } from '../error.js';
43
import { MaskError } from '../types.js';
54

6-
// We override the `toJSON` function to mask coordinate, because otherwise, it will be entirely
7-
// masked for plugins after the onExecuteDone phase (which have an impact for telemetry for example)
8-
function toJsonWithoutCoordinate(this: GraphQLError): GraphQLFormattedError {
9-
const toJSON: typeof GraphQLError.prototype.toJSON =
10-
(this as { _originalToJSON?: typeof GraphQLError.prototype.toJSON })._originalToJSON ??
11-
GraphQLError.prototype.toJSON;
12-
const json = toJSON.apply(this);
13-
// @ts-expect-error coordinate is readonly
14-
delete json.coordinate;
15-
16-
return json;
17-
}
18-
195
function serializeError(error: unknown) {
206
if (isGraphQLError(error)) {
217
return error.toJSON();
@@ -36,12 +22,6 @@ export const maskError: MaskError = (
3622
isDev = globalThis.process?.env?.['NODE_ENV'] === 'development',
3723
) => {
3824
if (isOriginalGraphQLError(error)) {
39-
if (!isDev) {
40-
Object.defineProperties(error, {
41-
toJSON: { value: toJsonWithoutCoordinate },
42-
_originalToJSON: { value: error.toJSON },
43-
});
44-
}
4525
return error;
4626
}
4727
const errorExtensions: Record<string, unknown> = {
@@ -67,20 +47,5 @@ export const maskError: MaskError = (
6747
errorExtensions['originalError'] = serializeError(error);
6848
}
6949

70-
const maskedError = createGraphQLError(message, errorOptions);
71-
72-
if (!isDev) {
73-
Object.defineProperties(maskedError, {
74-
toJSON: { value: toJsonWithoutCoordinate },
75-
_originalToJSON: { value: maskedError.toJSON },
76-
});
77-
if (maskedError.extensions['originalError'] instanceof GraphQLError) {
78-
Object.defineProperties(maskedError.extensions['originalError'], {
79-
toJSON: { value: toJsonWithoutCoordinate },
80-
_originalToJSON: { value: maskedError.extensions['originalError'].toJSON },
81-
});
82-
}
83-
}
84-
85-
return maskedError;
50+
return createGraphQLError(message, errorOptions);
8651
};

0 commit comments

Comments
 (0)