From b3533508223fdd5c6b7c2f4bc873c6761365ce54 Mon Sep 17 00:00:00 2001 From: shrugs Date: Mon, 18 May 2026 14:32:53 -0500 Subject: [PATCH 1/4] fix(ensapi): downgrade graphql input validation errors to debug Wrap the pino logger passed to graphql-yoga so ZodErrors (raised by @pothos/plugin-zod for invalid graphql inputs) log at debug instead of error. These are 4xx-class client errors, not server faults, and were flooding logs with stack traces for every malformed request. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/ensapi/src/omnigraph-api/yoga.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/apps/ensapi/src/omnigraph-api/yoga.ts b/apps/ensapi/src/omnigraph-api/yoga.ts index dd13148fa0..dd00f222c0 100644 --- a/apps/ensapi/src/omnigraph-api/yoga.ts +++ b/apps/ensapi/src/omnigraph-api/yoga.ts @@ -2,7 +2,9 @@ // import { maxDepthPlugin } from "@escape.tech/graphql-armor-max-depth"; // import { maxTokensPlugin } from "@escape.tech/graphql-armor-max-tokens"; +import { GraphQLError } from "graphql"; import { createYoga } from "graphql-yoga"; +import { ZodError } from "zod/v4"; import { makeLogger } from "@/lib/logger"; import { context } from "@/omnigraph-api/context"; @@ -10,6 +12,26 @@ import { schema } from "@/omnigraph-api/schema"; const logger = makeLogger("omnigraph"); +const isZodError = (value: unknown): boolean => + value instanceof ZodError || + (value instanceof GraphQLError && value.originalError instanceof ZodError); + +// Yoga logs every execution error at `error` level, including ZodErrors raised by +// @pothos/plugin-zod for invalid GraphQL inputs. Those are 4xx-class client errors, not +// server faults — downgrade them to `debug` so server logs aren't flooded with stack traces. +const yogaLogger = { + debug: logger.debug.bind(logger), + info: logger.info.bind(logger), + warn: logger.warn.bind(logger), + error: (err: unknown) => { + if (isZodError(err)) { + logger.debug({ err }, "GraphQL input validation rejected"); + return; + } + logger.error(err); + }, +}; + export const yoga = createYoga({ graphqlEndpoint: "*", schema, @@ -36,7 +58,7 @@ export const yoga = createYoga({ }, // integrate logging with pino - logging: logger, + logging: yogaLogger, plugins: [ // TODO: plugins From bdeb377ad24ba6ccc9564efaf761d22c89caf92e Mon Sep 17 00:00:00 2001 From: shrugs Date: Mon, 18 May 2026 14:39:49 -0500 Subject: [PATCH 2/4] fix: comments --- apps/ensapi/src/omnigraph-api/yoga.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/ensapi/src/omnigraph-api/yoga.ts b/apps/ensapi/src/omnigraph-api/yoga.ts index dd00f222c0..f167685beb 100644 --- a/apps/ensapi/src/omnigraph-api/yoga.ts +++ b/apps/ensapi/src/omnigraph-api/yoga.ts @@ -12,13 +12,14 @@ import { schema } from "@/omnigraph-api/schema"; const logger = makeLogger("omnigraph"); +// tests exact ZodError or GraphQLError-wrapped ZodError const isZodError = (value: unknown): boolean => value instanceof ZodError || (value instanceof GraphQLError && value.originalError instanceof ZodError); -// Yoga logs every execution error at `error` level, including ZodErrors raised by -// @pothos/plugin-zod for invalid GraphQL inputs. Those are 4xx-class client errors, not -// server faults — downgrade them to `debug` so server logs aren't flooded with stack traces. +// Yoga logs every execution error (including GraphQL input validaton errors) at `error` level, but +// those validation errors are expected, in general, so we downgrade them to `debug` so server logs +// aren't flooded with stack traces. const yogaLogger = { debug: logger.debug.bind(logger), info: logger.info.bind(logger), From 8314f1886dc74d3ef48157a632c22bf17c0ef50d Mon Sep 17 00:00:00 2001 From: shrugs Date: Tue, 19 May 2026 16:33:55 -0500 Subject: [PATCH 3/4] fix: bot notes (loop 1) Address review feedback from Greptile, CodeRabbit, and Vercel: - accept variadic args in yogaLogger.error so additional yoga args aren't dropped at the TS signature level (.bind for the others already forwards at runtime) - use structured logging form ({ err }, "GraphQL execution error") for the non-ZodError path to match the ZodError path Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/ensapi/src/omnigraph-api/yoga.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/ensapi/src/omnigraph-api/yoga.ts b/apps/ensapi/src/omnigraph-api/yoga.ts index f167685beb..e74f2a5ce4 100644 --- a/apps/ensapi/src/omnigraph-api/yoga.ts +++ b/apps/ensapi/src/omnigraph-api/yoga.ts @@ -24,12 +24,12 @@ const yogaLogger = { debug: logger.debug.bind(logger), info: logger.info.bind(logger), warn: logger.warn.bind(logger), - error: (err: unknown) => { + error: (err: unknown, ..._rest: unknown[]) => { if (isZodError(err)) { logger.debug({ err }, "GraphQL input validation rejected"); return; } - logger.error(err); + logger.error({ err }, "GraphQL execution error"); }, }; From adc60e0c57c5537efd76062037813bbc3d51597b Mon Sep 17 00:00:00 2001 From: shrugs Date: Tue, 19 May 2026 16:39:14 -0500 Subject: [PATCH 4/4] fix: bot notes (loop 2) Fix comment typo flagged by copilot review bot. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/ensapi/src/omnigraph-api/yoga.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ensapi/src/omnigraph-api/yoga.ts b/apps/ensapi/src/omnigraph-api/yoga.ts index e74f2a5ce4..118a799ad0 100644 --- a/apps/ensapi/src/omnigraph-api/yoga.ts +++ b/apps/ensapi/src/omnigraph-api/yoga.ts @@ -17,7 +17,7 @@ const isZodError = (value: unknown): boolean => value instanceof ZodError || (value instanceof GraphQLError && value.originalError instanceof ZodError); -// Yoga logs every execution error (including GraphQL input validaton errors) at `error` level, but +// Yoga logs every execution error (including GraphQL input validation errors) at `error` level, but // those validation errors are expected, in general, so we downgrade them to `debug` so server logs // aren't flooded with stack traces. const yogaLogger = {