From 8b952ff02eb706dc724cf10993055c36aabfcca2 Mon Sep 17 00:00:00 2001 From: Morgan Brown Date: Wed, 31 Dec 2025 16:30:47 +0200 Subject: [PATCH] Ensure graphql-depth-limit doesn't bork --- src/server.ts | 4 ++-- src/utils/safeDepthLimit.ts | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 src/utils/safeDepthLimit.ts diff --git a/src/server.ts b/src/server.ts index 5c4d03c..12157f4 100644 --- a/src/server.ts +++ b/src/server.ts @@ -14,8 +14,8 @@ import type { Response, } from 'express-serve-static-core'; import type { ParsedQs } from 'qs'; -import depthLimit from 'graphql-depth-limit'; import cors from 'cors'; +import safeDepthLimit from './utils/safeDepthLimit'; import resolvers from './resolvers'; import typeDefs from './schema'; import appSettings from './common/appSettings'; @@ -55,7 +55,7 @@ const httpServer = http.createServer(app); const server = new ApolloServer({ formatError, introspection: true, - validationRules: [depthLimit(appSettings.maxQueryDepth)], + validationRules: [safeDepthLimit(appSettings.maxQueryDepth)], typeDefs, resolvers, plugins: [ diff --git a/src/utils/safeDepthLimit.ts b/src/utils/safeDepthLimit.ts new file mode 100644 index 0000000..eb44d44 --- /dev/null +++ b/src/utils/safeDepthLimit.ts @@ -0,0 +1,35 @@ +import depthLimit from 'graphql-depth-limit'; +import type { ValidationContext } from 'graphql'; + +/** + * A wrapper around graphql-depth-limit that catches specific crashes caused by + * undefined fragments (which should be handled by standard validation but cause + * graphql-depth-limit to throw). + */ +const safeDepthLimit = + (maxDepth: number, options: any = {}, callback: any = () => undefined) => + (validationContext: ValidationContext) => { + try { + const validator = depthLimit(maxDepth, options, callback); + return validator(validationContext); + } catch (err: any) { + // graphql-depth-limit version 1.1.0 crashes on unknown fragments with + // TypeError: Cannot read properties of undefined (reading 'kind') + // We catch this specific error to allow standard GraphQL validation to handle the + // unknown fragment error, preventing a 500 Internal Server Error. + if ( + err instanceof TypeError && + err.message.includes( + "Cannot read properties of undefined (reading 'kind')", + ) + ) { + // If we catch this error, it means depth limit check failed due to invalid AST + // We return the context as is, skipping the depth check for this invalid query. + // Standard validation will subsequently fail with a proper 400 error. + return validationContext; + } + throw err; + } + }; + +export default safeDepthLimit;